other_video_transcoding 0.1.0 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a57410a06260109a616e8c52a66912c1232b94e1c6c9fa3b68193dc1928a806
4
- data.tar.gz: 2a3d7e2161ed9e5c057d706dca00505f3579840745e542af1fe65691144f88e4
3
+ metadata.gz: cfd039fdab5dca779448614baaf5f0e99b3d7dc883f97693919a016224e4b7aa
4
+ data.tar.gz: c97d8899ea867a018059d1896c3608e3982f8677f8fe81c7506097171c7591e8
5
5
  SHA512:
6
- metadata.gz: 01c79a2c59e29c90892ad9a9ced373852c3e81c86994d75ccd45d03b48502d0da4e891bc0852afb75954fe15cb0cbdffb2275b531ad34b33642463173db5d13c
7
- data.tar.gz: 527078a99a29100e1ffd6031f6d08ef44e9759a09157ab67a1831aa83d60c10544736cbbfe921394237877c640dc595aac530f5cf991e8dc29d9371f2152cb7f
6
+ metadata.gz: 1915b0bdacf95a0bdfe5e825497f9081571318aaf9423a10df614b0f5ab7a74949ebd6c6039c4ef09c5ce2d567dbe6a851019f996d64284a1ab0525a0a7c10e2
7
+ data.tar.gz: 64f23ade8dc74a15f8024313b66cd91b3298e80d4e39be391f47630ddd2aa812c67271bfa522794202dd33b4ce18b601c8cbf77a8b46078f288c050afd5eef3a
@@ -2,6 +2,62 @@
2
2
 
3
3
  This single document contains all of the notes created for each [release](https://github.com/donmelton/other_video_transcoding/releases).
4
4
 
5
+ ## [0.3.2](https://github.com/donmelton/other_video_transcoding/releases/tag/0.3.2)
6
+
7
+ Friday, September 11, 2020
8
+
9
+ * Modify `other-transcode` to use a new `ffmpeg` Matroksa muxer option so the `-disposition` option is once again honored when using `ffmpeg` version 4.3 and later.
10
+ * Change the codec ID from the default of `hev1` to `hvc1` for HEVC video in MP4 output from `other-transcode` to enable playback in QuickTime on macOS. Via [ #50](https://github.com/donmelton/other_video_transcoding/issues/50).
11
+ * Convert added SRT format subtitles to MOV-compatible format in MP4 output from `other-transcode`. Via [ #55](https://github.com/donmelton/other_video_transcoding/issues/55).
12
+
13
+ ## [0.3.1](https://github.com/donmelton/other_video_transcoding/releases/tag/0.3.1)
14
+
15
+ Tuesday, May 26, 2020
16
+
17
+ * Modify the `--preview-crop` option in `other-transcode` to show commands compatible with newer versions of `mpv`.
18
+ * No longer force a NTSC film frame rate for interlaced inputs in PAL MPEG-2 format.
19
+ * When using the `--dry-run` option in `other-transcode`, issue a warning instead of failing if the output or log files already exist.
20
+ * Add a link to another Docker container for Linux in the "README" document. Thanks, @ttyS0!
21
+
22
+ ## [0.3.0](https://github.com/donmelton/other_video_transcoding/releases/tag/0.3.0)
23
+
24
+ Thursday, February 27, 2020
25
+
26
+ * Add a `--scan` option to `other-transcode`. This prints media information and then exits, allowing easy identification of track numbers and formats. Via [ #11](https://github.com/donmelton/other_video_transcoding/issues/11).
27
+ * Add a `--mono-bitrate` option to `other-transcode`. This sets the mono audio bitrate, which is otherwise 50% of the stereo bitrate.
28
+ * Raise the maximum bitrates for audio in AAC format to 320 Kbps for stereo and 256 Kbps for mono. The default birates remain the same.
29
+ * Add a `--all-eac3` option to `other-transcode`. This uses the Dolby Digital Plus (Enhanced AC-3) format for all transcoded audio. The behavior of the `--eac3` option, which uses Dolby Digital Plus for surround audio only, remains the same.
30
+ * Add a `--keep-ac3-stereo` option to `other-transcode`. This copies stereo and mono audio in AC-3 format even when the original source bitrate is above the output transcoding bitrate.
31
+ * Add a `--pass-dts` option to `other-transcode`. This enables passthrough of audio in DTS and DTS-ES formats. However, such audio also in surround format will still be transcoded if that audio is output to a stereo-width track.
32
+ * Add `--rc-maxrate` and `--rc-bufsize` options to `other-transcode`. These set the ratecontrol maximum rate and/or the buffer size as a multiple of the video bitrate target, but only for certain encoders and ratecontrol systems.
33
+ * Add a `--x264-mbtree` option to `other-transcode`. This uses macroblock-tree ratecontrol and disables AVBR if in use.
34
+ * In order to ensure compatible H.264 levels, limit the number of reference frames when using the `x264` encoder with slower presets.
35
+ * Remove the deprecated `--name` option of `other-transcode`.
36
+ * Add a link to a Docker container for Linux in the "README" document. Thanks, @ttyS0!
37
+
38
+ ## [0.2.0](https://github.com/donmelton/other_video_transcoding/releases/tag/0.2.0)
39
+
40
+ Monday, January 13, 2020
41
+
42
+ * Allow `all` to be used as an argument to the `--add-audio` and `--add-subtitle` options of `other-transcode`, adding all audio tracks or all subtitle tracks. Via [ #3](https://github.com/donmelton/other_video_transcoding/issues/3).
43
+ * Add `original` as a width attribute to the `--main-audio` and `--add-audio` options of `other-transcode`. Unlike `stereo` and `surround`, this disables transcoding and always copies the selected track(s). Via [ #5](https://github.com/donmelton/other_video_transcoding/issues/5).
44
+ * Add a `--copy-video` option to `other-transcode`. This disables transcoding and copies the original video track to the output.
45
+ * No longer ignore any image-based subtitles added to MP4 output. Instead, let `ffmpeg` foolishly add DVD-style subtitles and (currently) fail when adding Blu-ray Disc-style subtitles.
46
+ * Deprecate the `--name` option of `other-transcode` because it doesn't make sense to name only the first output file from a tool which can take multiple inputs. The option still works for now, but using it issues a warning message. It will be removed in a future release.
47
+ * Remove warnings when other options disable the Nvidia video decoder, which could only happen if the `--burn-subtitle` or `--detelecine` options were used with the `--cuvid` option.
48
+
49
+ ## [0.1.1](https://github.com/donmelton/other_video_transcoding/releases/tag/0.1.1)
50
+
51
+ Friday, January 3, 2020
52
+
53
+ * Prevent passing full or partial paths to the `--name` option of `other-transcode`.
54
+ * Hide the path prefix when naming the program in `--help` output and in usage errors for both `other-transcode` and `ask-ffmpeg-log`.
55
+ * In the "README" document:
56
+ * Add warnings to avoid installing within virtual machines and about the possible need to use `sudo`.
57
+ * Add a link to additional documentation on the wiki for installing `ffprobe`, `ffmpeg`, `mkvpropedit` and `mpv` on Windows.
58
+ * Also explain how to install those same programs on macOS using Homebrew.
59
+ * Update all copyright notices to the year 2020.
60
+
5
61
  ## [0.1.0](https://github.com/donmelton/other_video_transcoding/releases/tag/0.1.0)
6
62
 
7
63
  Thursday, December 26, 2019
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2019 Don Melton
1
+ Copyright (c) 2019-2020 Don Melton
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -26,7 +26,7 @@ And many features are supported including:
26
26
  * Hardware-based video decoding for improved performance
27
27
  * Fallback to software video encoding when appropriate hardware is not available
28
28
  * Optional automatic and reliable video cropping
29
- * Adding audio and subtitle tracks by by language or title
29
+ * Adding audio and subtitle tracks by language or title
30
30
  * [Dolby Digital Plus](https://en.wikipedia.org/wiki/Dolby_Digital_Plus) (Enhanced AC-3) audio encoding
31
31
  * Burning image-based subtitles into video output to ease player compatibility
32
32
 
@@ -36,6 +36,8 @@ Additional documentation for this project is available in the [wiki](https://git
36
36
 
37
37
  ## Installation
38
38
 
39
+ _Avoid installing within [virtual machines](https://en.wikipedia.org/wiki/Virtual_machine) such as the [Windows Subsystem for Linux](https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux) since access to hardware video encoders may not be allowed, severely impacting performance._
40
+
39
41
  These tools work on Windows, Linux and macOS. They're packaged as a Gem and require Ruby. See "[Installing Ruby](https://www.ruby-lang.org/en/documentation/installation/)" if you don't have it on your platform.
40
42
 
41
43
  Use this command to install the package:
@@ -46,6 +48,8 @@ And this command to update it:
46
48
 
47
49
  gem update other_video_transcoding
48
50
 
51
+ _The commands to install and update may need prefixing with_ `sudo` _on some platforms._
52
+
49
53
  The `other-transcode` tool in this package requires other software to function properly, specifically these command line programs:
50
54
 
51
55
  * `ffprobe`
@@ -56,6 +60,22 @@ Optional crop previewing also requires the `mpv` command line program.
56
60
 
57
61
  See "[Download FFmpeg](https://ffmpeg.org/download.html)," "[MKVToolNix Downloads](https://mkvtoolnix.download/downloads.html)" and "[mpv Installation](https://mpv.io/installation/)" to find versions for your platform.
58
62
 
63
+ Additional documentation for installing these programs on Windows is available in the [wiki](https://github.com/donmelton/other_video_transcoding/wiki/Windows).
64
+
65
+ [Docker](https://en.wikipedia.org/wiki/Docker_(software)) containers for Linux, including installation instructions, are available here:
66
+
67
+ https://github.com/ttyS0/docker-transcode-nvidia
68
+
69
+ https://github.com/ttyS0/docker-transcode-vaapi
70
+
71
+ On macOS, all of these programs can be easily installed via [Homebrew](http://brew.sh/), an optional package manager:
72
+
73
+ brew install ffmpeg
74
+ brew install mkvtoolnix
75
+ brew install mpv
76
+
77
+ The `ffprobe` program is included within the `ffmpeg` package and the `mkvpropedit` program is included within the `mkvtoolnix` package.
78
+
59
79
  ## Usage
60
80
 
61
81
  Each tool in this package has several command line options. The `other-transcode` tool is the most complex with over 50 of its own. Use `--help` to list the options available for a specific tool, along with brief instructions on their usage:
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # ask-ffmpeg-log
4
4
  #
5
- # Copyright (c) 2019 Don Melton
5
+ # Copyright (c) 2019-2020 Don Melton
6
6
  #
7
7
 
8
8
  require 'abbrev'
@@ -15,18 +15,18 @@ module Transcoding
15
15
 
16
16
  class Command
17
17
  def about
18
- <<HERE
19
- ask-ffmpeg-log 0.1.0
20
- Copyright (c) 2019 Don Melton
21
- HERE
18
+ <<-HERE
19
+ ask-ffmpeg-log 0.3.2
20
+ Copyright (c) 2019-2020 Don Melton
21
+ HERE
22
22
  end
23
23
 
24
24
  def usage
25
- <<HERE
25
+ <<-HERE
26
26
  Report temporal information from ffmpeg-generated `.log` files
27
27
  containing encoding statistics.
28
28
 
29
- Usage: #{$PROGRAM_NAME} [OPTION]... [FILE|DIRECTORY]...
29
+ Usage: #{File.basename($PROGRAM_NAME)} [OPTION]... [FILE|DIRECTORY]...
30
30
 
31
31
  Options:
32
32
  --time sort results by time instead of speed
@@ -34,7 +34,7 @@ Options:
34
34
  --tabular use tab character as field delimiter and suppress labels
35
35
  -h, --help display this help and exit
36
36
  --version output version information and exit
37
- HERE
37
+ HERE
38
38
  end
39
39
 
40
40
  def initialize
@@ -65,11 +65,13 @@ HERE
65
65
  end
66
66
 
67
67
  fail UsageError, 'missing argument' if ARGV.empty?
68
+
68
69
  ARGV.each { |arg| process_input arg }
69
70
  complete
70
71
  exit
71
72
  rescue UsageError => e
72
- Kernel.warn "#{$PROGRAM_NAME}: #{e}\nTry `#{$PROGRAM_NAME} --help more` for more information."
73
+ Kernel.warn "#{$PROGRAM_NAME}: #{e}"
74
+ Kernel.warn "Try `#{File.basename($PROGRAM_NAME)} --help` for more information."
73
75
  exit false
74
76
  rescue StandardError => e
75
77
  Kernel.warn "#{$PROGRAM_NAME}: #{e}"
@@ -91,10 +93,12 @@ HERE
91
93
  if File.directory? input
92
94
  logs = Dir[input + File::SEPARATOR + '*.log']
93
95
  fail "does not contain `.log` files: #{input}" if logs.empty?
96
+
94
97
  @logs += logs
95
98
  @paths << input
96
99
  else
97
100
  fail "not a `.log` file: #{input}" unless File.extname(input) == '.log'
101
+
98
102
  @logs << File.absolute_path(input)
99
103
  @paths << File.dirname(input)
100
104
  end
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # other-transcode
4
4
  #
5
- # Copyright (c) 2019 Don Melton
5
+ # Copyright (c) 2019-2020 Don Melton
6
6
  #
7
7
 
8
8
  require 'English'
@@ -17,73 +17,72 @@ module Transcoding
17
17
 
18
18
  class Command
19
19
  def about
20
- <<HERE
21
- other-transcode 0.1.0
22
- Copyright (c) 2019 Don Melton
23
- HERE
20
+ <<-HERE
21
+ other-transcode 0.3.2
22
+ Copyright (c) 2019-2020 Don Melton
23
+ HERE
24
24
  end
25
25
 
26
26
  def usage1
27
- <<HERE
27
+ <<-HERE
28
28
  Transcode Blu-ray Disc or DVD rip into a smaller, more portable format
29
29
  while remaining high enough quality to be mistaken for the original.
30
30
 
31
- Usage: #{$PROGRAM_NAME} [OPTION]... [FILE]...
31
+ Usage: #{File.basename($PROGRAM_NAME)} [OPTION]... [FILE]...
32
32
 
33
33
  Creates Matroska `.mkv` format file in current working directory.
34
34
 
35
35
  Automatically selects a platform-specific hardware video encoder.
36
36
 
37
- HERE
37
+ HERE
38
38
  end
39
39
 
40
40
  def usage2
41
- <<HERE
41
+ <<-HERE
42
42
  Input options:
43
43
  --position TIME, --duration TIME
44
44
  start transcoding at position and/or limit to duration
45
45
  in seconds[.milliseconds] or [HH:]MM:SS[.m...] format
46
46
 
47
- HERE
47
+ HERE
48
48
  end
49
49
 
50
50
  def usage3
51
- <<HERE
51
+ <<-HERE
52
52
  Output options:
53
53
  --debug increase diagnostic information
54
+ --scan print media information and exit
54
55
  --preview-crop show commands to preview detected video crop and exit
55
- HERE
56
+ HERE
56
57
  end
57
58
 
58
59
  def usage4
59
- <<HERE
60
+ <<-HERE
60
61
  --print-crop print only detected video crop geometry and exit
61
62
  --mp4 output MP4 instead of Matroska `.mkv` format
62
- --name STRING set output filename, excluding format extension
63
- (default: based on input filename)
64
63
  --copy-track-names
65
64
  copy all input audio track names to output
66
- HERE
65
+ HERE
67
66
  end
68
67
 
69
68
  def usage5
70
- <<HERE
69
+ <<-HERE
71
70
  --max-muxing-queue-size SIZE
72
71
  set maximum number of packets to buffer when muxing
73
- HERE
72
+ HERE
74
73
  end
75
74
 
76
75
  def usage6
77
- <<HERE
76
+ <<-HERE
78
77
  -n, --dry-run don't transcode, just show `ffmpeg` command and exit
79
78
 
80
79
  Video options:
81
80
  --hevc use HEVC version of platform-specific video encoder
82
- HERE
81
+ HERE
83
82
  end
84
83
 
85
84
  def usage7
86
- <<HERE
85
+ <<-HERE
87
86
  --vt use Apple Video Toolbox encoder
88
87
  --nvenc use Nvidia video encoder
89
88
  --qsv use Intel Quick Sync video encoder
@@ -102,11 +101,11 @@ HERE
102
101
  --cuvid use Nvidia video decoder
103
102
  for H.264, VC-1, MPEG-2 and other formats
104
103
  (ignores scope set by `--decode`)
105
- HERE
104
+ HERE
106
105
  end
107
106
 
108
107
  def usage8
109
- <<HERE
108
+ <<-HERE
110
109
  --target [2160p=|1080p=|720p=|480p=]BITRATE
111
110
  set video bitrate target (default: based on input)
112
111
  or target for specific input resolution
@@ -114,11 +113,11 @@ HERE
114
113
  set video crop geometry (default: none)
115
114
  or automatically detect it
116
115
  --720p fit video within 1280x720 pixel bounds
117
- HERE
116
+ HERE
118
117
  end
119
118
 
120
119
  def usage9
121
- <<HERE
120
+ <<-HERE
122
121
  --1080p " " " 1920x1080 " "
123
122
  --deinterlace reduce interlace artifacts without changing frame rate
124
123
  (applied automatically for some inputs)
@@ -127,11 +126,15 @@ HERE
127
126
  --detelecine drop duplicate frames to restore original frame rate
128
127
  (disables any deinterlacing and forced frame rate)
129
128
  --no-filters disable any automatic adjustments via filters
130
- HERE
129
+ HERE
131
130
  end
132
131
 
133
132
  def usage10
134
- <<HERE
133
+ <<-HERE
134
+ --rc-maxrate FACTOR, --rc-bufsize FACTOR
135
+ set ratecontrol maximum rate and/or buffer size
136
+ as multiple of video bitrate target
137
+ --copy-video disable transcoding and copy original video track
135
138
 
136
139
  Apple Video Toolbox encoder options:
137
140
  --vt-allow-sw allow software encoding
@@ -172,22 +175,36 @@ Video Acceleration API encoder options:
172
175
 
173
176
  x264 software video encoder options:
174
177
  --x264-avbr use average variable bitrate (AVBR) ratecontrol
178
+ --x264-mbtree use macroblock-tree ratecontrol (disables AVBR if in use)
175
179
  --x264-quick increase encoding speed by 70-80%
176
180
  with no easily perceptible loss in video quality
177
181
  (avoids quality problems with some encoder presets)
178
- HERE
182
+ HERE
179
183
  end
180
184
 
181
185
  def usage11
182
- <<HERE
186
+ <<-HERE
183
187
 
184
188
  Audio options:
185
189
  --main-audio TRACK[=WIDTH]
186
190
  select main audio track by number (default: 1)
187
191
  with optional width (default: surround)
188
- --add-audio TRACK|LANGUAGE|STRING[=WIDTH]
192
+ HERE
193
+ end
194
+
195
+ def usage12
196
+ <<-HERE
197
+ (use `original` to disable transcoding)
198
+ HERE
199
+ end
200
+
201
+ def usage13
202
+ <<-HERE
203
+ --add-audio TRACK|all|LANGUAGE|STRING[=WIDTH]
189
204
  add single audio track by number
190
205
  including main audio track
206
+ or all audio tracks
207
+ excluding main audio track
191
208
  or audio tracks by language code
192
209
  excluding main audio track
193
210
  (in ISO 639-2 format, e.g.: `eng`)
@@ -195,22 +212,61 @@ Audio options:
195
212
  excluding main audio track
196
213
  (comparison is case-insensitve)
197
214
  with optional width (default: stereo)
215
+ HERE
216
+ end
217
+
218
+ def usage14
219
+ <<-HERE
220
+ (use `original` to disable transcoding)
221
+ HERE
222
+ end
223
+
224
+ def usage15
225
+ <<-HERE
198
226
  --surround-bitrate BITRATE
199
227
  set surround audio bitrate (default: 640)
200
228
  --stereo-bitrate BITRATE
201
229
  set stereo audio bitrate (default: 256)
230
+ HERE
231
+ end
232
+
233
+ def usage16
234
+ <<-HERE
235
+ --mono-bitrate BITRATE
236
+ set mono audio bitrate (default: 50% of stereo bitrate)
237
+ HERE
238
+ end
239
+
240
+ def usage17
241
+ <<-HERE
202
242
  --eac3 use Enhanced AC-3 format for surround audio
243
+ HERE
244
+ end
245
+
246
+ def usage18
247
+ <<-HERE
248
+ --all-eac3 " " " " " all audio
249
+ --keep-ac3-stereo
250
+ copy stereo and mono audio in AC-3 format
251
+ even when orginal bitrate is above transcoding bitrate
252
+ --pass-dts enable passthrough of audio in DTS and DTS-ES formats
253
+ HERE
254
+ end
255
+
256
+ def usage19
257
+ <<-HERE
203
258
 
204
259
  Subtitle options:
205
- --add-subtitle TRACK[=forced]|auto|LANGUAGE|STRING
260
+ --add-subtitle TRACK[=forced]|auto|all|LANGUAGE|STRING
206
261
  add single subtitle track by number
207
262
  optionally setting forced disposition
208
263
  or enable automatic addition of forced subtitle
209
- or add subtitle tracks by language code
264
+ or add all subtitle tracks
265
+ or subtitle tracks by language code
210
266
  (in ISO 639-2 format, e.g.: `eng`)
211
267
  or subtitle tracks with titles containing string
212
268
  (comparison is case-insensitve)
213
- (all variations exclude any burned track)
269
+ (variations exclude any burned track)
214
270
  --burn-subtitle TRACK|auto
215
271
  burn subtitle track by number into video
216
272
  or enable automatic burning of forced subtitle
@@ -223,17 +279,18 @@ Other options:
223
279
  --version output version information and exit
224
280
 
225
281
  Requires `ffprobe`, `ffmpeg` and `mkvpropedit`.
226
- HERE
282
+ HERE
227
283
  end
228
284
 
229
285
  def initialize
230
286
  @position = nil
231
287
  @duration = nil
232
288
  @debug = false
289
+ @scan = false
233
290
  @detect = false
234
291
  @preview = false
235
292
  @format = :mkv
236
- @name = nil
293
+ @mkv_options = []
237
294
  @copy_track_names = false
238
295
  @max_muxing_queue_size = nil
239
296
  @dry_run = false
@@ -255,6 +312,8 @@ HERE
255
312
  @rate = nil
256
313
  @detelecine = false
257
314
  @enable_filters = true
315
+ @maxrate = nil
316
+ @bufsize = nil
258
317
  @vt_allow_sw = false
259
318
  @nvenc_spatial_aq = nil
260
319
  @nvenc_temporal_aq = nil
@@ -270,6 +329,7 @@ HERE
270
329
  @amf_bframes = nil
271
330
  @vaapi_compression = nil
272
331
  @x264_avbr = false
332
+ @x264_mbtree = false
273
333
  @x264_quick = false
274
334
  @audio_selections = [{
275
335
  :track => 1,
@@ -279,8 +339,11 @@ HERE
279
339
  }]
280
340
  @surround_bitrate = 640
281
341
  @stereo_bitrate = 256
342
+ @mono_bitrate = nil
282
343
  @surround_encoder = 'ac3'
283
344
  @stereo_encoder = nil
345
+ @keep_ac3_stereo = false
346
+ @pass_dts = false
284
347
  @subtitle_selections = []
285
348
  @auto_add_subtitle = false
286
349
  @burn_subtitle_track = 0
@@ -295,12 +358,16 @@ HERE
295
358
  case arg
296
359
  when 'full'
297
360
  puts usage1 + usage2 + usage3 + usage4 + usage5 + usage6 +
298
- usage7 + usage8 + usage9 + usage10 + usage11
361
+ usage7 + usage8 + usage9 + usage10 + usage11 + usage12 +
362
+ usage13 + usage14 + usage15 + usage16 + usage17 +
363
+ usage18 + usage19
299
364
  when 'more'
300
365
  puts usage1 + usage2 + usage3 + usage4 + usage6 + usage7 +
301
- usage8 + usage9 + usage11
366
+ usage8 + usage9 + usage11 + usage13 + usage15 + usage16 +
367
+ usage17 + usage18 + usage19
302
368
  else
303
- puts usage1 + usage3 + usage6 + usage8 + usage11
369
+ puts usage1 + usage3 + usage6 + usage8 + usage11 + usage13 +
370
+ usage15 + usage17 + usage19
304
371
  end
305
372
 
306
373
  exit
@@ -316,11 +383,13 @@ HERE
316
383
  end
317
384
 
318
385
  fail UsageError, 'missing argument' if ARGV.empty?
386
+
319
387
  configure ARGV.first
320
388
  ARGV.each { |arg| process_input arg }
321
389
  exit
322
390
  rescue UsageError => e
323
- Kernel.warn "#{$PROGRAM_NAME}: #{e}\nTry `#{$PROGRAM_NAME} --help more` for more information."
391
+ Kernel.warn "#{$PROGRAM_NAME}: #{e}"
392
+ Kernel.warn "Try `#{File.basename($PROGRAM_NAME)} --help` for more information."
324
393
  exit false
325
394
  rescue StandardError => e
326
395
  Kernel.warn "#{$PROGRAM_NAME}: #{e}"
@@ -343,6 +412,10 @@ HERE
343
412
  @debug = true
344
413
  end
345
414
 
415
+ opts.on '--scan' do
416
+ @scan = true
417
+ end
418
+
346
419
  opts.on '--preview-crop' do
347
420
  @detect = true
348
421
  @preview = true
@@ -357,10 +430,6 @@ HERE
357
430
  @format = :mp4
358
431
  end
359
432
 
360
- opts.on '--name ARG' do |arg|
361
- @name = arg
362
- end
363
-
364
433
  opts.on '--copy-track-names' do
365
434
  @copy_track_names = true
366
435
  end
@@ -410,10 +479,12 @@ HERE
410
479
 
411
480
  opts.on '--[no-]10-bit' do |arg|
412
481
  @ten_bit = arg
482
+ @encoder = nil if @encoder == 'copy'
413
483
  end
414
484
 
415
485
  opts.on '--preset ARG' do |arg|
416
486
  @preset = arg
487
+ @encoder = nil if @encoder == 'copy'
417
488
  end
418
489
 
419
490
  opts.on '--decode ARG' do |arg|
@@ -450,6 +521,8 @@ HERE
450
521
  else
451
522
  @target = [arg.to_i, 1].max
452
523
  end
524
+
525
+ @encoder = nil if @encoder == 'copy'
453
526
  end
454
527
 
455
528
  opts.on '--crop ARG' do |arg|
@@ -461,22 +534,27 @@ HERE
461
534
  else
462
535
  fail UsageError, "invalid crop geometry: #{arg}"
463
536
  end
537
+
538
+ @encoder = nil if @encoder == 'copy'
464
539
  end
465
540
 
466
541
  opts.on '--720p' do
467
542
  @max_width = 1280
468
543
  @max_height = 720
544
+ @encoder = nil if @encoder == 'copy'
469
545
  end
470
546
 
471
547
  opts.on '--1080p' do
472
548
  @max_width = 1920
473
549
  @max_height = 1080
550
+ @encoder = nil if @encoder == 'copy'
474
551
  end
475
552
 
476
553
  opts.on '--deinterlace' do
477
554
  @deinterlace = true
478
555
  @detelecine = false
479
556
  @enable_filters = false
557
+ @encoder = nil if @encoder == 'copy' and @decoder_type != :cuvid
480
558
  end
481
559
 
482
560
  opts.on '--rate ARG' do |arg|
@@ -499,6 +577,7 @@ HERE
499
577
 
500
578
  @detelecine = false
501
579
  @enable_filters = false
580
+ @encoder = nil if @encoder == 'copy'
502
581
  end
503
582
 
504
583
  opts.on '--detelecine' do
@@ -506,12 +585,36 @@ HERE
506
585
  @deinterlace = false
507
586
  @rate = nil
508
587
  @enable_filters = false
588
+ @encoder = nil if @encoder == 'copy'
509
589
  end
510
590
 
511
591
  opts.on '--no-filters' do
512
592
  @enable_filters = false
513
593
  end
514
594
 
595
+ opts.on '--rc-maxrate ARG', Float do |arg|
596
+ @maxrate = arg
597
+ @encoder = nil if @encoder == 'copy'
598
+ end
599
+
600
+ opts.on '--rc-bufsize ARG', Float do |arg|
601
+ @bufsize = arg
602
+ @encoder = nil if @encoder == 'copy'
603
+ end
604
+
605
+ opts.on '--copy-video' do
606
+ @encoder = 'copy'
607
+ @hevc = false
608
+ @ten_bit = nil
609
+ @preset = nil
610
+ @target = nil
611
+ @crop = nil
612
+ @rate = nil
613
+ @detelecine = false
614
+ @enable_filters = false
615
+ @burn_subtitle_track = 0
616
+ end
617
+
515
618
  opts.on '--vt-allow-sw' do
516
619
  @encoder = @hevc ? 'hevc_videotoolbox' : 'h264_videotoolbox'
517
620
  @vt_allow_sw = true
@@ -592,6 +695,14 @@ HERE
592
695
  @encoder = 'libx264'
593
696
  @hevc = false
594
697
  @x264_avbr = true
698
+ @x264_mbtree = false
699
+ end
700
+
701
+ opts.on '--x264-mbtree' do
702
+ @encoder = 'libx264'
703
+ @hevc = false
704
+ @x264_mbtree = true
705
+ @x264_avbr = false
595
706
  end
596
707
 
597
708
  opts.on '--x264-quick' do
@@ -602,7 +713,7 @@ HERE
602
713
  end
603
714
 
604
715
  opts.on '--main-audio ARG' do |arg|
605
- if arg =~ /^([0-9]+)(?:=(surround|stereo))?$/
716
+ if arg =~ /^([0-9]+)(?:=(stereo|surround|original))?$/
606
717
  @audio_selections[0][:track] = $1.to_i
607
718
  @audio_selections[0][:width] = $2.to_sym unless $2.nil?
608
719
  else
@@ -611,7 +722,7 @@ HERE
611
722
  end
612
723
 
613
724
  opts.on '--add-audio ARG' do |arg|
614
- if arg =~ /^([^=]+)(?:=(surround|stereo))?$/
725
+ if arg =~ /^([^=]+)(?:=(stereo|surround|original))?$/
615
726
  scope = $1
616
727
  width = $2
617
728
 
@@ -646,10 +757,27 @@ HERE
646
757
  @stereo_bitrate = arg
647
758
  end
648
759
 
760
+ opts.on '--mono-bitrate ARG', Integer do |arg|
761
+ @mono_bitrate = arg
762
+ end
763
+
649
764
  opts.on '--eac3' do
650
765
  @surround_encoder = 'eac3'
651
766
  end
652
767
 
768
+ opts.on '--all-eac3' do
769
+ @surround_encoder = 'eac3'
770
+ @stereo_encoder = 'eac3'
771
+ end
772
+
773
+ opts.on '--keep-ac3-stereo' do
774
+ @keep_ac3_stereo = true
775
+ end
776
+
777
+ opts.on '--pass-dts' do
778
+ @pass_dts = true
779
+ end
780
+
653
781
  opts.on '--add-subtitle ARG' do |arg|
654
782
  if arg =~ /^([0-9]+)(?:=(forced))?$|^(auto)$|^([a-z]{3})$|^(.*)$/
655
783
  @subtitle_selections += [{
@@ -675,6 +803,8 @@ HERE
675
803
  else
676
804
  fail UsageError, "invalid subtitle track: #{arg}"
677
805
  end
806
+
807
+ @encoder = nil if @encoder == 'copy'
678
808
  end
679
809
  end
680
810
 
@@ -699,7 +829,13 @@ HERE
699
829
  @audio_selections.uniq!
700
830
  @subtitle_selections.uniq!
701
831
  @surround_bitrate = [[@surround_bitrate, 256].max, (@surround_encoder == 'ac3' ? 640 : 768)].min
702
- @stereo_bitrate = [[@stereo_bitrate, 128].max, 256].min
832
+ @stereo_bitrate = [[@stereo_bitrate, 128].max, (@stereo_encoder == 'eac3' ? 768 : 320)].min
833
+
834
+ if @mono_bitrate.nil?
835
+ @mono_bitrate = @stereo_bitrate / 2
836
+ else
837
+ @mono_bitrate = [[@mono_bitrate, 64].max, (@stereo_encoder == 'eac3' ? 768 : 256)].min
838
+ end
703
839
 
704
840
  [
705
841
  ['ffprobe', '-loglevel', 'quiet', '-version'],
@@ -709,7 +845,7 @@ HERE
709
845
  verify_tool_availability command
710
846
  end
711
847
 
712
- return if @detect
848
+ return if @scan or @detect
713
849
 
714
850
  encoders = find_encoders
715
851
 
@@ -734,7 +870,7 @@ HERE
734
870
  else
735
871
  @encoder.sub!(/^h264/, 'hevc') if @hevc
736
872
 
737
- unless @dry_run or encoders =~ /#{@encoder}/
873
+ unless @dry_run or @encoder == 'copy' or encoders =~ /#{@encoder}/
738
874
  fail "video encoder not available: #{@encoder}"
739
875
  end
740
876
  end
@@ -752,6 +888,11 @@ HERE
752
888
  @stereo_encoder = 'aac'
753
889
  end
754
890
  end
891
+
892
+ if @format == :mkv
893
+ capabilities = get_muxer_capabilities
894
+ @mkv_options = ['-default_mode', 'passthrough'] if capabilities =~ /passthrough/
895
+ end
755
896
  end
756
897
 
757
898
  def verify_tool_availability(command)
@@ -829,22 +970,51 @@ HERE
829
970
  $CHILD_STATUS.exitstatus == 0
830
971
  end
831
972
 
973
+ def get_muxer_capabilities
974
+ Kernel.warn 'Getting muxer capabilities...'
975
+ output = ''
976
+
977
+ begin
978
+ IO.popen([
979
+ 'ffmpeg',
980
+ '-loglevel', 'quiet',
981
+ '-h', 'muxer=matroska'
982
+ ], :err=>[:child, :out]) do |io|
983
+ io.each do |line|
984
+ Kernel.warn line if @debug
985
+ output += line
986
+ end
987
+ end
988
+ rescue SystemCallError => e
989
+ raise "getting muxer capabilities failed: #{e}"
990
+ end
991
+
992
+ fail 'getting muxer capabilities failed' unless $CHILD_STATUS.exitstatus == 0
993
+
994
+ output
995
+ end
996
+
832
997
  def process_input(path)
833
998
  seconds = Time.now.tv_sec
834
999
 
835
- unless @detect
836
- output_path = (@name.nil? ? File.basename(path, '.*') : @name) + '.' + @format.to_s
837
- fail "output file already exists: #{output_path}" if File.exist? output_path
1000
+ unless @scan or @detect
1001
+ output_path = File.basename(path, '.*') + '.' + @format.to_s
1002
+ fail_or_warn "output file already exists: #{output_path}" if File.exist? output_path
838
1003
 
839
1004
  log_path = output_path + '.log'
840
- fail "log file already exists: #{log_path}" if File.exist? log_path
1005
+ fail_or_warn "log file already exists: #{log_path}" if File.exist? log_path
841
1006
 
842
1007
  tmp_log_path = "_ffmpeg_#{rand(10000..99999)}_#{$PROCESS_ID}.#{@format.to_s}.log"
843
- fail "log file already exists: #{tmp_log_path}" if File.exist? tmp_log_path
1008
+ fail_or_warn "log file already exists: #{tmp_log_path}" if File.exist? tmp_log_path
844
1009
  end
845
1010
 
846
1011
  media_info = scan_media(path)
847
1012
 
1013
+ if @scan
1014
+ print_media_info media_info
1015
+ return
1016
+ end
1017
+
848
1018
  video, burn_subtitle = get_video_streams(media_info)
849
1019
  fail "video track not found: #{path}" if video.nil?
850
1020
 
@@ -855,7 +1025,7 @@ HERE
855
1025
  crop = detect_crop(media_info, video)
856
1026
 
857
1027
  if @detect
858
- present_crop(crop, path)
1028
+ present_crop crop, path
859
1029
  return
860
1030
  else
861
1031
  Kernel.warn "crop = #{crop[:width]}:#{crop[:height]}:#{crop[:x]}:#{crop[:y]}"
@@ -888,13 +1058,13 @@ HERE
888
1058
  '-stats'
889
1059
  ] + time_options +
890
1060
  decode_options + [
891
- '-i', "#{path}"
1061
+ '-i', path
892
1062
  ] + (@max_muxing_queue_size.nil? ? [] : ['-max_muxing_queue_size', @max_muxing_queue_size.to_s]) +
893
1063
  encode_options +
894
1064
  get_audio_options(media_info) +
895
1065
  get_subtitle_options(media_info, burn_subtitle) + [
896
1066
  '-metadata:g', 'title='
897
- ] + (@format == :mp4 ? ['-movflags', 'disable_chpl'] : []) + [
1067
+ ] + (@format == :mkv ? @mkv_options : ['-movflags', 'disable_chpl']) + [
898
1068
  output_path
899
1069
  ]
900
1070
 
@@ -939,17 +1109,25 @@ HERE
939
1109
  FileUtils.mv tmp_log_path, log_path
940
1110
  end
941
1111
 
942
- assemble_log(log_path, output)
1112
+ assemble_log log_path, output
943
1113
 
944
1114
  if @format == :mp4
945
1115
  Kernel.warn 'Done.'
946
1116
  else
947
- add_track_statistics_tags(output_path)
1117
+ add_track_statistics_tags output_path
948
1118
  end
949
1119
 
950
1120
  Kernel.warn "\nElapsed time: #{seconds_to_time(Time.now.tv_sec - seconds)}\n\n"
951
1121
  end
952
1122
 
1123
+ def fail_or_warn(message)
1124
+ if @dry_run
1125
+ Kernel.warn "#{$PROGRAM_NAME}: #{message}"
1126
+ else
1127
+ fail message
1128
+ end
1129
+ end
1130
+
953
1131
  def scan_media(path)
954
1132
  Kernel.warn 'Scanning media...'
955
1133
  output = ''
@@ -984,6 +1162,93 @@ HERE
984
1162
  media_info
985
1163
  end
986
1164
 
1165
+ def print_media_info(media_info)
1166
+ video = nil
1167
+ audio_streams = []
1168
+ subtitles = []
1169
+
1170
+ media_info['streams'].each do |stream|
1171
+ case stream['codec_type']
1172
+ when 'video'
1173
+ video = stream if video.nil?
1174
+ when 'audio'
1175
+ audio_streams += [stream]
1176
+ when 'subtitle'
1177
+ subtitles += [stream]
1178
+ end
1179
+ end
1180
+
1181
+ puts media_info['format']['filename']
1182
+ size = "#{video['width']} x #{video['height']}"
1183
+ print " format = #{video['codec_name']} / #{size} / #{video['avg_frame_rate']} fps"
1184
+ bitrate = get_bitrate(video)
1185
+ puts bitrate.nil? ? '' : " / #{bitrate} Kbps"
1186
+ duration = media_info['format']['duration'].to_f
1187
+ time = seconds_to_time(duration.to_i)
1188
+ milliseconds = duration.to_s.sub(/^[0-9]+(\.[0-9]+)$/, '\1')
1189
+ time += milliseconds unless milliseconds == '.0'
1190
+ puts " duration = #{time}"
1191
+ index = 0
1192
+
1193
+ audio_streams.each do |stream|
1194
+ index += 1
1195
+ puts "\##{index} audio:"
1196
+ codec_name = stream['codec_name']
1197
+ print " format = #{codec_name}"
1198
+
1199
+ if codec_name == 'dts'
1200
+ profile = stream.fetch('profile', 'DTS')
1201
+ print " (#{profile})" unless profile == 'DTS'
1202
+ end
1203
+
1204
+ print ' / '
1205
+ layout = stream.fetch('channel_layout', '')
1206
+
1207
+ if layout.empty?
1208
+ channels = stream['channels'].to_i
1209
+ print "#{channels} " + (channels > 1 ? 'channels' : 'channel')
1210
+ else
1211
+ print "#{layout}"
1212
+ end
1213
+
1214
+ bitrate = get_bitrate(stream)
1215
+ puts bitrate.nil? ? '' : " / #{bitrate} Kbps"
1216
+ puts " language = #{stream.fetch('tags', {}).fetch('language', '')}"
1217
+ title = stream.fetch('tags', {}).fetch('title', '')
1218
+ puts " title = #{title}" unless title.empty?
1219
+ end
1220
+
1221
+ index = 0
1222
+
1223
+ subtitles.each do |stream|
1224
+ index += 1
1225
+ puts "\##{index} subtitle:"
1226
+ print " format = #{stream['codec_name']}"
1227
+ frames = stream.fetch('tags', {}).fetch('NUMBER_OF_FRAMES-eng', '')
1228
+ puts frames.empty? ? '' : " / #{frames} " + (frames == 1 ? 'frame' : 'frames')
1229
+ puts " language = #{stream.fetch('tags', {}).fetch('language', '')}"
1230
+ title = stream.fetch('tags', {}).fetch('title', '')
1231
+ puts " title = #{title}" unless title.empty?
1232
+ default = (stream['disposition']['default'] == 1)
1233
+ forced = (stream['disposition']['forced'] == 1)
1234
+
1235
+ if default or forced
1236
+ puts ' flags = ' +
1237
+ (default ? 'default' : '') +
1238
+ ((default and forced) ? ' / ' : '') +
1239
+ (forced ? 'forced' : '')
1240
+ end
1241
+ end
1242
+ end
1243
+
1244
+ def get_bitrate(stream)
1245
+ bitrate = stream.fetch('bit_rate', '')
1246
+ bitrate = stream.fetch('tags', {}).fetch('BPS-eng', '') if bitrate.empty?
1247
+ return nil if bitrate.empty?
1248
+
1249
+ bitrate.to_i / 1000
1250
+ end
1251
+
987
1252
  def detect_crop(media_info, video)
988
1253
  Kernel.warn 'Detecting crop...'
989
1254
  duration = media_info['format']['duration'].to_f
@@ -1106,10 +1371,10 @@ HERE
1106
1371
  drawbox_string = "#{crop[:x]}:#{crop[:y]}:#{crop[:width]}:#{crop[:height]}"
1107
1372
  puts
1108
1373
  puts escape_command([
1109
- 'mpv', '--no-audio', '--vf', "lavfi=[drawbox=#{drawbox_string}:invert:1]", path
1374
+ 'mpv', '--no-audio', "--vf=lavfi=[drawbox=#{drawbox_string}:invert:1]", path
1110
1375
  ])
1111
1376
  puts escape_command([
1112
- 'mpv', '--no-audio', '--vf', "crop=#{crop_string}", path
1377
+ 'mpv', '--no-audio', "--vf=crop=#{crop_string}", path
1113
1378
  ])
1114
1379
  puts
1115
1380
  puts escape_command([
@@ -1239,13 +1504,7 @@ HERE
1239
1504
  overlay_filter = nil
1240
1505
  else
1241
1506
  overlay_filter = "[0:#{burn_subtitle['index']}]overlay"
1242
-
1243
- unless cuvid_decoder.nil?
1244
- Kernel.warn '**********'
1245
- Kernel.warn "burning subtitle disables video decoder: #{cuvid_decoder}"
1246
- Kernel.warn '**********'
1247
- cuvid_decoder = nil
1248
- end
1507
+ cuvid_decoder = nil
1249
1508
  end
1250
1509
 
1251
1510
  deinterlace = @deinterlace
@@ -1255,7 +1514,7 @@ HERE
1255
1514
  if video['avg_frame_rate'] == '30000/1001' or video['field_order'] != 'progressive'
1256
1515
  deinterlace = true
1257
1516
 
1258
- if video['codec_name'] == 'mpeg2video'
1517
+ if video['codec_name'] == 'mpeg2video' and video['avg_frame_rate'] != '25/1'
1259
1518
  rate = '24000/1001'
1260
1519
  end
1261
1520
  end
@@ -1265,7 +1524,7 @@ HERE
1265
1524
 
1266
1525
  if deinterlace
1267
1526
  if cuvid_decoder.nil?
1268
- frame_rate_filter = 'yadif=deint=interlaced'
1527
+ frame_rate_filter = 'yadif=deint=interlaced' unless @encoder == 'copy'
1269
1528
  else
1270
1529
  cuvid_options += ['-deint:v', 'adaptive']
1271
1530
  end
@@ -1278,14 +1537,8 @@ HERE
1278
1537
  end
1279
1538
 
1280
1539
  if @detelecine
1281
- unless cuvid_decoder.nil?
1282
- Kernel.warn '**********'
1283
- Kernel.warn "detelecine disables video decoder: #{cuvid_decoder}"
1284
- Kernel.warn '**********'
1285
- cuvid_decoder = nil
1286
- end
1287
-
1288
1540
  frame_rate_filter = 'fieldmatch=order=tff:combmatch=none,decimate'
1541
+ cuvid_decoder = nil
1289
1542
  end
1290
1543
 
1291
1544
  width = video['width'].to_i
@@ -1373,12 +1626,16 @@ HERE
1373
1626
  conversion_filter = nil
1374
1627
  end
1375
1628
 
1376
- filter = overlay_filter.nil? ? '' : overlay_filter
1377
- filter += frame_rate_filter.nil? ? '' : ",#{frame_rate_filter}"
1378
- filter += crop_filter.nil? ? '' : ",#{crop_filter}"
1379
- filter += scale_filter.nil? ? '' : ",#{scale_filter}"
1380
- filter += conversion_filter.nil? ? '' : ",#{conversion_filter}"
1381
- filter.sub!(/^,/, '')
1629
+ if @encoder == 'copy'
1630
+ filter = ''
1631
+ else
1632
+ filter = overlay_filter.nil? ? '' : overlay_filter
1633
+ filter += frame_rate_filter.nil? ? '' : ",#{frame_rate_filter}"
1634
+ filter += crop_filter.nil? ? '' : ",#{crop_filter}"
1635
+ filter += scale_filter.nil? ? '' : ",#{scale_filter}"
1636
+ filter += conversion_filter.nil? ? '' : ",#{conversion_filter}"
1637
+ filter.sub!(/^,/, '')
1638
+ end
1382
1639
 
1383
1640
  if overlay_filter.nil?
1384
1641
  encode_options = [
@@ -1412,15 +1669,19 @@ HERE
1412
1669
  if width > 1920 or height > 1080
1413
1670
  bitrate = @target_2160p
1414
1671
  max_bitrate = 40000
1672
+ max_dpb_mbs = 184320
1415
1673
  elsif width > 1280 or height > 720
1416
1674
  bitrate = @target_1080p
1417
1675
  max_bitrate = 20000
1676
+ max_dpb_mbs = 32768
1418
1677
  elsif width > 720 or height > 576
1419
1678
  bitrate = @target_720p
1420
1679
  max_bitrate = 10000
1680
+ max_dpb_mbs = 18000
1421
1681
  else
1422
1682
  bitrate = @target_480p
1423
1683
  max_bitrate = 5000
1684
+ max_dpb_mbs = 8100
1424
1685
 
1425
1686
  unless hdr
1426
1687
  color_primaries = pal ? 'bt470bg' : 'smpte170m'
@@ -1430,7 +1691,22 @@ HERE
1430
1691
 
1431
1692
  bitrate = @target unless @target.nil?
1432
1693
  bitrate = [bitrate, max_bitrate].min
1433
- maxrate = bitrate * 3
1694
+ maxrate = 0
1695
+ bufsize = 0
1696
+
1697
+ if @encoder =~ /(nvenc|hevc_qsv|libx26[45])$/
1698
+ if @maxrate.nil?
1699
+ maxrate = bitrate * 3
1700
+ else
1701
+ maxrate = [[(bitrate * @maxrate).to_i, (bitrate * 1.5).to_i].max, bitrate * 3].min
1702
+ end
1703
+
1704
+ if @bufsize.nil?
1705
+ bufsize = maxrate if @encoder =~ /^libx26[45]$/
1706
+ else
1707
+ bufsize = [[(bitrate * @bufsize).to_i, bitrate].max, bitrate * 4].min
1708
+ end
1709
+ end
1434
1710
 
1435
1711
  if @preset.nil? or @preset == 'none'
1436
1712
  preset = nil
@@ -1457,12 +1733,17 @@ HERE
1457
1733
  end
1458
1734
 
1459
1735
  fail "invalid preset for encoder: #{@preset}" unless valid
1736
+
1460
1737
  preset = @preset
1461
1738
  end
1462
1739
 
1463
1740
  Kernel.warn 'Stream mapping:'
1464
- text = "#{sprintf("%2d", video['index'])} = #{@encoder} / #{bitrate} Kbps"
1465
- text += " / #{preset}" unless preset.nil?
1741
+ text = "#{sprintf("%2d", video['index'])} = #{@encoder}"
1742
+
1743
+ unless @encoder == 'copy'
1744
+ text += " / #{bitrate} Kbps"
1745
+ text += " / #{preset}" unless preset.nil?
1746
+ end
1466
1747
 
1467
1748
  unless burn_subtitle.nil?
1468
1749
  text += " / #{sprintf("%d", burn_subtitle['index'])} = #{burn_subtitle['codec_name']} / burn"
@@ -1471,9 +1752,9 @@ HERE
1471
1752
  Kernel.warn text
1472
1753
  encode_options += ['-c:v', @encoder]
1473
1754
  encode_options += ['-pix_fmt:v', (@encoder =~ /(nvenc|qsv)$/ ? 'p010le' : 'yuv420p10le')] if @ten_bit
1474
- encode_options += ['-b:v', "#{bitrate}k"]
1475
- encode_options += ['-maxrate:v', "#{maxrate}k"] if @encoder =~ /(nvenc|hevc_qsv|libx26[45])$/
1476
- encode_options += ['-bufsize:v', "#{maxrate}k"] if @encoder =~ /^libx26[45]$/
1755
+ encode_options += ['-b:v', "#{bitrate}k"] unless @encoder == 'copy'
1756
+ encode_options += ['-maxrate:v', "#{maxrate}k"] if maxrate > 0
1757
+ encode_options += ['-bufsize:v', "#{bufsize}k"] if bufsize > 0
1477
1758
  encode_options += ['-preset:v', preset] unless preset.nil?
1478
1759
  encode_options += ['-allow_sw:v', '1'] if @encoder =~ /videotoolbox$/ and @vt_allow_sw
1479
1760
 
@@ -1527,14 +1808,31 @@ HERE
1527
1808
 
1528
1809
  if @encoder == 'libx264'
1529
1810
  encode_options += ['-x264opts:v', 'ratetol=inf'] if @x264_avbr
1530
- encode_options += ['-mbtree:v', '0']
1811
+ encode_options += ['-mbtree:v', '0'] unless @x264_mbtree
1531
1812
 
1532
- if @preset.nil? and @x264_quick
1533
- encode_options += [
1534
- '-refs:v', '1',
1535
- '-rc-lookahead:v', '30',
1536
- '-partitions:v', 'none'
1537
- ]
1813
+ if @preset.nil?
1814
+ if @x264_quick
1815
+ encode_options += [
1816
+ '-refs:v', '1',
1817
+ '-rc-lookahead:v', '30',
1818
+ '-partitions:v', 'none'
1819
+ ]
1820
+ end
1821
+ else
1822
+ max_refs = [(max_dpb_mbs / (((width + 15) / 16) * ((height + 15) / 16))), 16].min
1823
+
1824
+ case @preset
1825
+ when 'slow'
1826
+ refs = 5
1827
+ when 'slower'
1828
+ refs = 8
1829
+ when 'veryslow', 'placebo'
1830
+ refs = 16
1831
+ else
1832
+ refs = 0
1833
+ end
1834
+
1835
+ encode_options += ['-refs:v', max_refs.to_s] if refs > max_refs
1538
1836
  end
1539
1837
  end
1540
1838
 
@@ -1542,14 +1840,21 @@ HERE
1542
1840
  encode_options += ['-profile:v', 'high'] if @encoder =~ /^(h264_nvenc|h264_amf|libx264)$/
1543
1841
  end
1544
1842
 
1843
+ unless @encoder == 'copy'
1844
+ encode_options += [
1845
+ '-color_primaries:v', color_primaries,
1846
+ '-color_trc:v', color_trc,
1847
+ '-colorspace:v', colorspace
1848
+ ]
1849
+ end
1850
+
1545
1851
  encode_options += [
1546
- '-color_primaries:v', color_primaries,
1547
- '-color_trc:v', color_trc,
1548
- '-colorspace:v', colorspace,
1549
1852
  '-metadata:s:v', 'title=',
1550
1853
  '-disposition:v', 'default'
1551
1854
  ]
1552
1855
 
1856
+ encode_options += ['-tag:v', 'hvc1'] if @format == :mp4 and @hevc
1857
+
1553
1858
  [decode_options, encode_options]
1554
1859
  end
1555
1860
 
@@ -1575,7 +1880,14 @@ HERE
1575
1880
  audio_tracks = [{
1576
1881
  :stream => main_audio,
1577
1882
  :width => width,
1578
- :bitrate => width == :surround ? @surround_bitrate : @stereo_bitrate
1883
+ :bitrate => case width
1884
+ when :stereo
1885
+ @stereo_bitrate
1886
+ when :surround
1887
+ @surround_bitrate
1888
+ when :original
1889
+ nil
1890
+ end
1579
1891
  }]
1580
1892
 
1581
1893
  titles = {}
@@ -1588,7 +1900,15 @@ HERE
1588
1900
  end
1589
1901
 
1590
1902
  width = selection[:width]
1591
- bitrate = width == :surround ? @surround_bitrate : @stereo_bitrate
1903
+
1904
+ bitrate = case width
1905
+ when :stereo
1906
+ @stereo_bitrate
1907
+ when :surround
1908
+ @surround_bitrate
1909
+ when :original
1910
+ nil
1911
+ end
1592
1912
 
1593
1913
  unless selection[:track].nil?
1594
1914
  audio_track = 0
@@ -1614,7 +1934,8 @@ HERE
1614
1934
  media_info['streams'].each do |stream|
1615
1935
  next if stream['codec_type'] != 'audio'
1616
1936
 
1617
- if stream.fetch('tags', {}).fetch('language', '') == selection[:language] and
1937
+ if (selection[:language] == 'all' or
1938
+ stream.fetch('tags', {}).fetch('language', '') == selection[:language]) and
1618
1939
  stream['index'] != main_audio['index']
1619
1940
  audio_tracks += [{
1620
1941
  :stream => stream,
@@ -1658,28 +1979,37 @@ HERE
1658
1979
  bitrate = nil
1659
1980
  channels = nil
1660
1981
 
1661
- if track[:width] == :surround
1662
- if codec_name == @surround_encoder or codec_name == 'ac3'
1982
+ if track[:width] == :original
1663
1983
  encoder = 'copy'
1664
- elsif input_channels > 2
1665
- encoder = @surround_encoder
1666
- bitrate = @surround_bitrate
1984
+ else
1985
+ dts = (codec_name == 'dts' and track[:stream].fetch('profile', 'DTS') =~ /^DTS(?:-ES)?$/)
1986
+
1987
+ if track[:width] == :surround
1988
+ if codec_name == @surround_encoder or
1989
+ codec_name == 'ac3' or
1990
+ (@pass_dts and dts)
1991
+ encoder = 'copy'
1992
+ elsif input_channels > 2
1993
+ encoder = @surround_encoder
1994
+ bitrate = @surround_bitrate
1995
+ end
1667
1996
  end
1668
- end
1669
1997
 
1670
- if encoder.nil?
1671
- if input_channels <= 2 and (codec_name == 'aac' or
1672
- ((codec_name == @surround_encoder or codec_name == 'ac3') and
1673
- (track[:stream]['bit_rate'].to_i / 1000) <= @stereo_bitrate))
1674
- encoder = 'copy'
1675
- else
1676
- encoder = @stereo_encoder
1677
- bitrate = @stereo_bitrate
1998
+ if encoder.nil?
1999
+ if input_channels <= 2 and (codec_name == 'aac' or
2000
+ ((codec_name == @surround_encoder or codec_name == 'ac3') and
2001
+ (@keep_ac3_stereo or (track[:stream]['bit_rate'].to_i / 1000) <= @stereo_bitrate)) or
2002
+ (@pass_dts and dts))
2003
+ encoder = 'copy'
2004
+ else
2005
+ encoder = @stereo_encoder
2006
+ bitrate = @stereo_bitrate
1678
2007
 
1679
- if input_channels > 2
1680
- channels = 2
1681
- elsif input_channels == 1
1682
- bitrate = @stereo_bitrate / 2
2008
+ if input_channels > 2
2009
+ channels = 2
2010
+ elsif input_channels == 1
2011
+ bitrate = @mono_bitrate
2012
+ end
1683
2013
  end
1684
2014
  end
1685
2015
  end
@@ -1762,7 +2092,8 @@ HERE
1762
2092
  media_info['streams'].each do |stream|
1763
2093
  next if stream['codec_type'] != 'subtitle'
1764
2094
 
1765
- if stream.fetch('tags', {}).fetch('language', '') == selection[:language]
2095
+ if (selection[:language] == 'all' or
2096
+ stream.fetch('tags', {}).fetch('language', '') == selection[:language])
1766
2097
  subtitles += [stream]
1767
2098
  end
1768
2099
  end
@@ -1779,10 +2110,7 @@ HERE
1779
2110
  end
1780
2111
  end
1781
2112
 
1782
- unless force_subtitle.nil?
1783
- subtitles = [force_subtitle] + subtitles
1784
- end
1785
-
2113
+ subtitles = [force_subtitle] + subtitles unless force_subtitle.nil?
1786
2114
  subtitles.uniq!
1787
2115
  options = []
1788
2116
  index = 0
@@ -1790,9 +2118,6 @@ HERE
1790
2118
  subtitles.each do |subtitle|
1791
2119
  next if (not burn_subtitle.nil?) and burn_subtitle['index'] == subtitle['index']
1792
2120
 
1793
- next if @format == :mp4 and
1794
- (subtitle['codec_name'] == 'hdmv_pgs_subtitle' or subtitle['codec_name'] == 'dvd_subtitle')
1795
-
1796
2121
  force = (index == 0 and not force_subtitle.nil?)
1797
2122
  text = "#{sprintf("%2d", subtitle['index'])} = #{subtitle['codec_name']}"
1798
2123
  text += ' / force' if force
@@ -1802,7 +2127,7 @@ HERE
1802
2127
 
1803
2128
  options += [
1804
2129
  '-map', "0:#{subtitle['index']}",
1805
- "-c:s:#{index}", 'copy',
2130
+ "-c:s:#{index}", ((@format == :mp4 and subtitle['codec_name'] == 'subrip') ? 'mov_text' : 'copy'),
1806
2131
  "-disposition:s:#{index}", (force ? 'default+forced' : '0')
1807
2132
  ]
1808
2133