other_video_transcoding 0.2.0 → 0.5.0

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: fbe4654304564db44ba76d5b6b4a805a853e4ae2fca1238f69d7ceac6152970b
4
- data.tar.gz: 5104621d3963ddacfd90796a2dd9cad57fc04f03c47e6122cc7dccd3794df16c
3
+ metadata.gz: e5caa1866dd6d3035704fb8977f21d682291ebfd46a6496974399a6876b13d33
4
+ data.tar.gz: b7c206ee00b2162bfea7b9c27f7566c879225a32efcfbf7a09fd7a9fc88f8200
5
5
  SHA512:
6
- metadata.gz: 6eec714eb59091c7ee48b74a4ac6dba65b3333bfa3dbb76b24ef5afb334e0c7434cc16234fe8e056cb7328eecc820794a8f54433082a49db6e06c02b812c690d
7
- data.tar.gz: ff5ee96313996a08b9433e223c64e01b492c7bebc1735c5533d6f263373c56e8202d13e78bd9c07221f6b08c502577d9ae8701a53f5741a4ce57911b8024b826
6
+ metadata.gz: d1c667e8c485d1ab70a4c035aa53915365aa6225cab6487f0488c37fa99eb7632e1ffc262ab3f256a55d8e43c71caaa20ed1d8dd64194a275972dbc1c65dee38
7
+ data.tar.gz: a47799076252ff46103419e41def057edfc4e63ec299b477f2360f7aad0ed866c14d0ff5f5ac2f8a3d1aeaf7a40fc47a2e3f4d203bc88c128cd0ce893f6fd22d
@@ -2,6 +2,63 @@
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.5.0](https://github.com/donmelton/other_video_transcoding/releases/tag/0.5.0)
6
+
7
+ Tuesday, November 24, 2020
8
+
9
+ * Add `--qsv-decoder` and `--qsv-device` options to `other-transcode`, both of which enable the scoped use of the Intel Quick Sync Video (QSV) decoder instead of the generic hardware decoder. These options can significantly speed operation of the QSV encoder, invoked via `--qsv`. It's recommended that `--decode all` be included when using these options to decode all video input formats. The `--qsv-device` option allows selection of specific hardware by number or path depending on platform. Please note that deinterlacing, cropping, scaling or using other filters will disable QSV's format-specific decoders.
10
+ * Remove all deprecated options and arguments from `other-transcode`.
11
+
12
+ ## [0.4.0](https://github.com/donmelton/other_video_transcoding/releases/tag/0.4.0)
13
+
14
+ Sunday, November 1, 2020
15
+
16
+ * Modify the behavior and augment the capabilities of both encoding and decoding when using Nvidia hardware with `other-transcode`. This is necessary for compatibility with unleased versions of `ffmpeg` which are now built using the new Nvidia Software Development Kit (SDK) version 11.0. This SDK changes default encoder behavior and adds new presets which allow finer control of the performance/quality trade-off when transcoding video. To allow maximum performance, `other-transcode` no longer enables some quality settings by default:
17
+ * Multipass mode, now accessible via a new `--nvenc-multipass` option. Be advised that any improved quality from enabling multipass mode is probably not worth the performance impact.
18
+ * Spatial and temporal adaptive quantization (AQ), accessible via the `--nvenc-spatial-aq` and `--nvenc-temporal-aq` options. While enabling spatial AQ is still useful in reducing color banding for some inputs, be advised that enabling temporal AQ is probably not necessary and can cause some other side effects.
19
+ * Add support for seven new Nvidia encoder presets to `other-transcode`. Use `--preset p1` for best performance and `--preset p7` for best quality. It's not necessary to use `--preset p4` since that's the default. See the [Nvidia preset migration guide](https://docs.nvidia.com/video-technologies/video-codec-sdk/nvenc-preset-migration-guide/index.html) to understand how these presets work and how they map to older behavior.
20
+ * Add a `--nvenc-rc-mode` option to `other-transcode` for backward comaptibility with `ffmpeg` version 4.3.1 and older.
21
+ * Add `--cuda` and `--no-cuda` options to `other-transcode`. These options enable or disable the scoped use of the Nvidia CUDA hardware decoder instead of the generic hardware decoder. By default the CUDA _decoder_ is enabled when using the Nvidia video _encoder_, but disabled when using other encoders.
22
+ * Deprecate the `--cuvid` option in `other-transcode` because the CUDA decoder is faster and more flexible.
23
+ * Deprecate `--preset none` in `other-transcode` because it's no longer necessary.
24
+ * Always use hyphen-based spellings of Nvidia AQ options in `ffmpeg` commands generated by `other-transcode`.
25
+ * Add `--x264-params` and `--x265-params` options to `other-transcode` for _very_ advanced manipulation of the `x264` and `x265` software encoders.
26
+ * Modify `other-transcode` to assume a video input without a `field_order` tag is progressive instead of interlaced so a deinterlace fliter is not automatically and incorrectly applied to that video. This avoids problems with some 4K Ultra HD Blu-ray rips.
27
+ * Update the link to Docker containers for Linux in the "README" document. Thanks, @ttyS0!
28
+
29
+ ## [0.3.2](https://github.com/donmelton/other_video_transcoding/releases/tag/0.3.2)
30
+
31
+ Friday, September 11, 2020
32
+
33
+ * 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.
34
+ * 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).
35
+ * 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).
36
+
37
+ ## [0.3.1](https://github.com/donmelton/other_video_transcoding/releases/tag/0.3.1)
38
+
39
+ Tuesday, May 26, 2020
40
+
41
+ * Modify the `--preview-crop` option in `other-transcode` to show commands compatible with newer versions of `mpv`.
42
+ * No longer force a NTSC film frame rate for interlaced inputs in PAL MPEG-2 format.
43
+ * When using the `--dry-run` option in `other-transcode`, issue a warning instead of failing if the output or log files already exist.
44
+ * Add a link to another Docker container for Linux in the "README" document. Thanks, @ttyS0!
45
+
46
+ ## [0.3.0](https://github.com/donmelton/other_video_transcoding/releases/tag/0.3.0)
47
+
48
+ Thursday, February 27, 2020
49
+
50
+ * 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).
51
+ * Add a `--mono-bitrate` option to `other-transcode`. This sets the mono audio bitrate, which is otherwise 50% of the stereo bitrate.
52
+ * 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.
53
+ * 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.
54
+ * 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.
55
+ * 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.
56
+ * 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.
57
+ * Add a `--x264-mbtree` option to `other-transcode`. This uses macroblock-tree ratecontrol and disables AVBR if in use.
58
+ * In order to ensure compatible H.264 levels, limit the number of reference frames when using the `x264` encoder with slower presets.
59
+ * Remove the deprecated `--name` option of `other-transcode`.
60
+ * Add a link to a Docker container for Linux in the "README" document. Thanks, @ttyS0!
61
+
5
62
  ## [0.2.0](https://github.com/donmelton/other_video_transcoding/releases/tag/0.2.0)
6
63
 
7
64
  Monday, January 13, 2020
data/README.md CHANGED
@@ -62,6 +62,10 @@ See "[Download FFmpeg](https://ffmpeg.org/download.html)," "[MKVToolNix Download
62
62
 
63
63
  Additional documentation for installing these programs on Windows is available in the [wiki](https://github.com/donmelton/other_video_transcoding/wiki/Windows).
64
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-other-transcode
68
+
65
69
  On macOS, all of these programs can be easily installed via [Homebrew](http://brew.sh/), an optional package manager:
66
70
 
67
71
  brew install ffmpeg
@@ -15,14 +15,14 @@ module Transcoding
15
15
 
16
16
  class Command
17
17
  def about
18
- <<HERE
19
- ask-ffmpeg-log 0.2.0
18
+ <<-HERE
19
+ ask-ffmpeg-log 0.5.0
20
20
  Copyright (c) 2019-2020 Don Melton
21
- HERE
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
 
@@ -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,6 +65,7 @@ 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
@@ -92,10 +93,12 @@ HERE
92
93
  if File.directory? input
93
94
  logs = Dir[input + File::SEPARATOR + '*.log']
94
95
  fail "does not contain `.log` files: #{input}" if logs.empty?
96
+
95
97
  @logs += logs
96
98
  @paths << input
97
99
  else
98
100
  fail "not a `.log` file: #{input}" unless File.extname(input) == '.log'
101
+
99
102
  @logs << File.absolute_path(input)
100
103
  @paths << File.dirname(input)
101
104
  end
@@ -17,14 +17,14 @@ module Transcoding
17
17
 
18
18
  class Command
19
19
  def about
20
- <<HERE
21
- other-transcode 0.2.0
20
+ <<-HERE
21
+ other-transcode 0.5.0
22
22
  Copyright (c) 2019-2020 Don Melton
23
- HERE
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
 
@@ -34,54 +34,55 @@ 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
63
  --copy-track-names
63
64
  copy all input audio track names to output
64
- HERE
65
+ HERE
65
66
  end
66
67
 
67
68
  def usage5
68
- <<HERE
69
+ <<-HERE
69
70
  --max-muxing-queue-size SIZE
70
71
  set maximum number of packets to buffer when muxing
71
- HERE
72
+ HERE
72
73
  end
73
74
 
74
75
  def usage6
75
- <<HERE
76
+ <<-HERE
76
77
  -n, --dry-run don't transcode, just show `ffmpeg` command and exit
77
78
 
78
79
  Video options:
79
80
  --hevc use HEVC version of platform-specific video encoder
80
- HERE
81
+ HERE
81
82
  end
82
83
 
83
84
  def usage7
84
- <<HERE
85
+ <<-HERE
85
86
  --vt use Apple Video Toolbox encoder
86
87
  --nvenc use Nvidia video encoder
87
88
  --qsv use Intel Quick Sync video encoder
@@ -92,19 +93,24 @@ HERE
92
93
  --10-bit, --no-10-bit
93
94
  use 10-bit pixel format (default: not used for H.264,
94
95
  used for HEVC with Nvidia, Intel and x265 encoders)
95
- --preset NAME|none
96
- apply video encoder preset or disable default settings
96
+ --preset NAME apply video encoder preset
97
97
  --decode vc1|all|none
98
98
  set scope of automatic hardware decoder acceleration
99
99
  (default: vc1 for VC-1 format only)
100
- --cuvid use Nvidia video decoder
101
- for H.264, VC-1, MPEG-2 and other formats
102
- (ignores scope set by `--decode`)
103
- HERE
100
+ --cuda, --no-cuda
101
+ enable or disable scoped use of Nvidia video decoder
102
+ instead of generic hardware decoder
103
+ (default: enabled when using Nvidia video encoder,
104
+ disabled when using other encoders)
105
+ --qsv-decoder enable scoped use of Intel Quick Sync video decoder
106
+ instead of generic hardware decoder
107
+ --qsv-device DEVICE
108
+ enable scoped use of QSV decoder for specific device
109
+ HERE
104
110
  end
105
111
 
106
112
  def usage8
107
- <<HERE
113
+ <<-HERE
108
114
  --target [2160p=|1080p=|720p=|480p=]BITRATE
109
115
  set video bitrate target (default: based on input)
110
116
  or target for specific input resolution
@@ -112,11 +118,11 @@ HERE
112
118
  set video crop geometry (default: none)
113
119
  or automatically detect it
114
120
  --720p fit video within 1280x720 pixel bounds
115
- HERE
121
+ HERE
116
122
  end
117
123
 
118
124
  def usage9
119
- <<HERE
125
+ <<-HERE
120
126
  --1080p " " " 1920x1080 " "
121
127
  --deinterlace reduce interlace artifacts without changing frame rate
122
128
  (applied automatically for some inputs)
@@ -125,28 +131,34 @@ HERE
125
131
  --detelecine drop duplicate frames to restore original frame rate
126
132
  (disables any deinterlacing and forced frame rate)
127
133
  --no-filters disable any automatic adjustments via filters
128
- HERE
134
+ HERE
129
135
  end
130
136
 
131
137
  def usage10
132
- <<HERE
138
+ <<-HERE
139
+ --rc-maxrate FACTOR, --rc-bufsize FACTOR
140
+ set ratecontrol maximum rate and/or buffer size
141
+ as multiple of video bitrate target
133
142
  --copy-video disable transcoding and copy original video track
134
143
 
135
144
  Apple Video Toolbox encoder options:
136
145
  --vt-allow-sw allow software encoding
137
146
 
138
147
  Nvidia video encoder options:
139
- --nvenc-spatial-aq, --no-nvenc-spatial-aq
140
- enable or disable spatial AQ (default: enabled)
141
- --nvenc-temporal-aq, --no-nvenc-temporal-aq
142
- enable or disable temporal AQ
143
- (default: enabled for H.264, disabled for HEVC)
148
+ --nvenc-spatial-aq
149
+ enable spatial adaptive quantization (AQ)
150
+ --nvenc-temporal-aq
151
+ enable temporal adaptive quantization (AQ)
144
152
  --nvenc-lookahead FRAMES
145
153
  set number of frames to look ahead for ratecontrol
154
+ --nvenc-multipass qres|fullres
155
+ set multipass encoding resolution
146
156
  --nvenc-refs FRAMES
147
157
  set number of reference frames
148
158
  --nvenc-bframes FRAMES
149
159
  set maximum number of B-frames
160
+ --nvenc-rc-mode vbr|vbr_hq
161
+ set ratecontrol mode (default: vbr)
150
162
 
151
163
  Intel Quick Sync video encoder options:
152
164
  --qsv-refs FRAMES
@@ -171,30 +183,37 @@ Video Acceleration API encoder options:
171
183
 
172
184
  x264 software video encoder options:
173
185
  --x264-avbr use average variable bitrate (AVBR) ratecontrol
186
+ --x264-mbtree use macroblock-tree ratecontrol (disables AVBR if in use)
174
187
  --x264-quick increase encoding speed by 70-80%
175
188
  with no easily perceptible loss in video quality
176
189
  (avoids quality problems with some encoder presets)
177
- HERE
190
+ --x264-params KEY=VALUE[:KEY=VALUE]...
191
+ override x264 configuration (disables other x264 options)
192
+
193
+ x265 software video encoder options:
194
+ --x265-params KEY=VALUE[:KEY=VALUE]...
195
+ override x265 configuration
196
+ HERE
178
197
  end
179
198
 
180
199
  def usage11
181
- <<HERE
200
+ <<-HERE
182
201
 
183
202
  Audio options:
184
203
  --main-audio TRACK[=WIDTH]
185
204
  select main audio track by number (default: 1)
186
205
  with optional width (default: surround)
187
- HERE
206
+ HERE
188
207
  end
189
208
 
190
209
  def usage12
191
- <<HERE
210
+ <<-HERE
192
211
  (use `original` to disable transcoding)
193
- HERE
212
+ HERE
194
213
  end
195
214
 
196
215
  def usage13
197
- <<HERE
216
+ <<-HERE
198
217
  --add-audio TRACK|all|LANGUAGE|STRING[=WIDTH]
199
218
  add single audio track by number
200
219
  including main audio track
@@ -207,22 +226,49 @@ HERE
207
226
  excluding main audio track
208
227
  (comparison is case-insensitve)
209
228
  with optional width (default: stereo)
210
- HERE
229
+ HERE
211
230
  end
212
231
 
213
232
  def usage14
214
- <<HERE
233
+ <<-HERE
215
234
  (use `original` to disable transcoding)
216
- HERE
235
+ HERE
217
236
  end
218
237
 
219
238
  def usage15
220
- <<HERE
239
+ <<-HERE
221
240
  --surround-bitrate BITRATE
222
241
  set surround audio bitrate (default: 640)
223
242
  --stereo-bitrate BITRATE
224
243
  set stereo audio bitrate (default: 256)
244
+ HERE
245
+ end
246
+
247
+ def usage16
248
+ <<-HERE
249
+ --mono-bitrate BITRATE
250
+ set mono audio bitrate (default: 50% of stereo bitrate)
251
+ HERE
252
+ end
253
+
254
+ def usage17
255
+ <<-HERE
225
256
  --eac3 use Enhanced AC-3 format for surround audio
257
+ HERE
258
+ end
259
+
260
+ def usage18
261
+ <<-HERE
262
+ --all-eac3 " " " " " all audio
263
+ --keep-ac3-stereo
264
+ copy stereo and mono audio in AC-3 format
265
+ even when orginal bitrate is above transcoding bitrate
266
+ --pass-dts enable passthrough of audio in DTS and DTS-ES formats
267
+ HERE
268
+ end
269
+
270
+ def usage19
271
+ <<-HERE
226
272
 
227
273
  Subtitle options:
228
274
  --add-subtitle TRACK[=forced]|auto|all|LANGUAGE|STRING
@@ -247,17 +293,18 @@ Other options:
247
293
  --version output version information and exit
248
294
 
249
295
  Requires `ffprobe`, `ffmpeg` and `mkvpropedit`.
250
- HERE
296
+ HERE
251
297
  end
252
298
 
253
299
  def initialize
254
300
  @position = nil
255
301
  @duration = nil
256
302
  @debug = false
303
+ @scan = false
257
304
  @detect = false
258
305
  @preview = false
259
306
  @format = :mkv
260
- @name = nil
307
+ @mkv_options = []
261
308
  @copy_track_names = false
262
309
  @max_muxing_queue_size = nil
263
310
  @dry_run = false
@@ -266,7 +313,8 @@ HERE
266
313
  @ten_bit = nil
267
314
  @preset = nil
268
315
  @decode_scope = :vc1
269
- @decoder_type = nil
316
+ @decode_method = nil
317
+ @qsv_device = nil
270
318
  @target_2160p = nil
271
319
  @target_1080p = nil
272
320
  @target_720p = nil
@@ -279,12 +327,16 @@ HERE
279
327
  @rate = nil
280
328
  @detelecine = false
281
329
  @enable_filters = true
330
+ @maxrate = nil
331
+ @bufsize = nil
282
332
  @vt_allow_sw = false
283
- @nvenc_spatial_aq = nil
284
- @nvenc_temporal_aq = nil
333
+ @nvenc_spatial_aq = false
334
+ @nvenc_temporal_aq = false
285
335
  @nvenc_lookahead = nil
336
+ @nvenc_multipass = nil
286
337
  @nvenc_refs = nil
287
338
  @nvenc_bframes = nil
339
+ @nvenc_rc_mode = 'vbr'
288
340
  @qsv_refs = nil
289
341
  @qsv_bframes = nil
290
342
  @amf_quality = nil
@@ -294,7 +346,10 @@ HERE
294
346
  @amf_bframes = nil
295
347
  @vaapi_compression = nil
296
348
  @x264_avbr = false
349
+ @x264_mbtree = false
297
350
  @x264_quick = false
351
+ @x264_params = nil
352
+ @x265_params = nil
298
353
  @audio_selections = [{
299
354
  :track => 1,
300
355
  :language => nil,
@@ -303,8 +358,11 @@ HERE
303
358
  }]
304
359
  @surround_bitrate = 640
305
360
  @stereo_bitrate = 256
361
+ @mono_bitrate = nil
306
362
  @surround_encoder = 'ac3'
307
363
  @stereo_encoder = nil
364
+ @keep_ac3_stereo = false
365
+ @pass_dts = false
308
366
  @subtitle_selections = []
309
367
  @auto_add_subtitle = false
310
368
  @burn_subtitle_track = 0
@@ -320,12 +378,15 @@ HERE
320
378
  when 'full'
321
379
  puts usage1 + usage2 + usage3 + usage4 + usage5 + usage6 +
322
380
  usage7 + usage8 + usage9 + usage10 + usage11 + usage12 +
323
- usage13 + usage14 + usage15
381
+ usage13 + usage14 + usage15 + usage16 + usage17 +
382
+ usage18 + usage19
324
383
  when 'more'
325
384
  puts usage1 + usage2 + usage3 + usage4 + usage6 + usage7 +
326
- usage8 + usage9 + usage11 + usage13 + usage15
385
+ usage8 + usage9 + usage11 + usage13 + usage15 + usage16 +
386
+ usage17 + usage18 + usage19
327
387
  else
328
- puts usage1 + usage3 + usage6 + usage8 + usage11 + usage13 + usage15
388
+ puts usage1 + usage3 + usage6 + usage8 + usage11 + usage13 +
389
+ usage15 + usage17 + usage19
329
390
  end
330
391
 
331
392
  exit
@@ -341,6 +402,7 @@ HERE
341
402
  end
342
403
 
343
404
  fail UsageError, 'missing argument' if ARGV.empty?
405
+
344
406
  configure ARGV.first
345
407
  ARGV.each { |arg| process_input arg }
346
408
  exit
@@ -369,6 +431,10 @@ HERE
369
431
  @debug = true
370
432
  end
371
433
 
434
+ opts.on '--scan' do
435
+ @scan = true
436
+ end
437
+
372
438
  opts.on '--preview-crop' do
373
439
  @detect = true
374
440
  @preview = true
@@ -383,13 +449,6 @@ HERE
383
449
  @format = :mp4
384
450
  end
385
451
 
386
- opts.on '--name ARG' do |arg|
387
- @name = arg
388
- Kernel.warn '**********'
389
- Kernel.warn 'Using deprecated option: --name'
390
- Kernel.warn '**********'
391
- end
392
-
393
452
  opts.on '--copy-track-names' do
394
453
  @copy_track_names = true
395
454
  end
@@ -456,8 +515,17 @@ HERE
456
515
  end
457
516
  end
458
517
 
459
- opts.on '--cuvid' do
460
- @decoder_type = :cuvid
518
+ opts.on '--[no-]cuda' do |arg|
519
+ @decode_method = arg ? 'cuda' : 'auto'
520
+ end
521
+
522
+ opts.on '--qsv-decoder' do
523
+ @decode_method = 'qsv'
524
+ end
525
+
526
+ opts.on '--qsv-device ARG' do |arg|
527
+ @qsv_device = arg
528
+ @decode_method = 'qsv'
461
529
  end
462
530
 
463
531
  opts.on '--target ARG' do |arg|
@@ -514,7 +582,7 @@ HERE
514
582
  @deinterlace = true
515
583
  @detelecine = false
516
584
  @enable_filters = false
517
- @encoder = nil if @encoder == 'copy' and @decoder_type != :cuvid
585
+ @encoder = nil if @encoder == 'copy'
518
586
  end
519
587
 
520
588
  opts.on '--rate ARG' do |arg|
@@ -552,6 +620,16 @@ HERE
552
620
  @enable_filters = false
553
621
  end
554
622
 
623
+ opts.on '--rc-maxrate ARG', Float do |arg|
624
+ @maxrate = arg
625
+ @encoder = nil if @encoder == 'copy'
626
+ end
627
+
628
+ opts.on '--rc-bufsize ARG', Float do |arg|
629
+ @bufsize = arg
630
+ @encoder = nil if @encoder == 'copy'
631
+ end
632
+
555
633
  opts.on '--copy-video' do
556
634
  @encoder = 'copy'
557
635
  @hevc = false
@@ -570,14 +648,14 @@ HERE
570
648
  @vt_allow_sw = true
571
649
  end
572
650
 
573
- opts.on '--[no-]nvenc-spatial-aq' do |arg|
651
+ opts.on '--nvenc-spatial-aq' do
574
652
  @encoder = @hevc ? 'hevc_nvenc' : 'h264_nvenc'
575
- @nvenc_spatial_aq = arg
653
+ @nvenc_spatial_aq = true
576
654
  end
577
655
 
578
- opts.on '--[no-]nvenc-temporal-aq' do |arg|
656
+ opts.on '--nvenc-temporal-aq' do
579
657
  @encoder = @hevc ? 'hevc_nvenc' : 'h264_nvenc'
580
- @nvenc_temporal_aq = arg
658
+ @nvenc_temporal_aq = true
581
659
  end
582
660
 
583
661
  opts.on '--nvenc-lookahead ARG', Integer do |arg|
@@ -585,6 +663,17 @@ HERE
585
663
  @nvenc_lookahead = [[arg, 0].max, 32].min
586
664
  end
587
665
 
666
+ opts.on '--nvenc-multipass ARG' do |arg|
667
+ @encoder = @hevc ? 'hevc_nvenc' : 'h264_nvenc'
668
+
669
+ @nvenc_multipass = case arg
670
+ when 'qres', 'fullres'
671
+ arg
672
+ else
673
+ fail UsageError, "invalid multipass resolution argument: #{arg}"
674
+ end
675
+ end
676
+
588
677
  opts.on '--nvenc-refs ARG', Integer do |arg|
589
678
  @encoder = @hevc ? 'hevc_nvenc' : 'h264_nvenc'
590
679
  @nvenc_refs = [arg, 0].max
@@ -595,6 +684,17 @@ HERE
595
684
  @nvenc_bframes = [[arg, 0].max, 4].min
596
685
  end
597
686
 
687
+ opts.on '--nvenc-rc-mode ARG' do |arg|
688
+ @encoder = @hevc ? 'hevc_nvenc' : 'h264_nvenc'
689
+
690
+ @nvenc_rc_mode = case arg
691
+ when 'vbr', 'vbr_hq'
692
+ arg
693
+ else
694
+ fail UsageError, "invalid rate control argument: #{arg}"
695
+ end
696
+ end
697
+
598
698
  opts.on '--qsv-refs ARG', Integer do |arg|
599
699
  @encoder = @hevc ? 'hevc_qsv' : 'h264_qsv'
600
700
  @qsv_refs = [arg, 0].max
@@ -645,15 +745,49 @@ HERE
645
745
  @encoder = 'libx264'
646
746
  @hevc = false
647
747
  @x264_avbr = true
748
+ @x264_mbtree = false
749
+ @x264_params = nil
750
+ end
751
+
752
+ opts.on '--x264-mbtree' do
753
+ @encoder = 'libx264'
754
+ @hevc = false
755
+ @x264_mbtree = true
756
+ @x264_avbr = false
757
+ @x264_params = nil
648
758
  end
649
759
 
650
760
  opts.on '--x264-quick' do
651
761
  @encoder = 'libx264'
652
762
  @hevc = false
653
763
  @x264_quick = true
764
+ @x264_params = nil
654
765
  @preset = nil
655
766
  end
656
767
 
768
+ opts.on '--x264-params ARG' do |arg|
769
+ arg.split ':' do |param|
770
+ fail UsageError, "invalid argument: #{arg}" unless param =~ /^[\w\-]+=[\w\-\.,]+$/
771
+ end
772
+
773
+ @encoder = 'libx264'
774
+ @hevc = false
775
+ @x264_params = arg
776
+ @x264_avbr = false
777
+ @x264_mbtree = true
778
+ @x264_quick = false
779
+ end
780
+
781
+ opts.on '--x265-params ARG' do |arg|
782
+ arg.split ':' do |param|
783
+ fail UsageError, "invalid argument: #{arg}" unless param =~ /^[\w\-]+=[\w\-\.,]+$/
784
+ end
785
+
786
+ @encoder = 'libx265'
787
+ @hevc = true
788
+ @x265_params = arg
789
+ end
790
+
657
791
  opts.on '--main-audio ARG' do |arg|
658
792
  if arg =~ /^([0-9]+)(?:=(stereo|surround|original))?$/
659
793
  @audio_selections[0][:track] = $1.to_i
@@ -699,10 +833,27 @@ HERE
699
833
  @stereo_bitrate = arg
700
834
  end
701
835
 
836
+ opts.on '--mono-bitrate ARG', Integer do |arg|
837
+ @mono_bitrate = arg
838
+ end
839
+
702
840
  opts.on '--eac3' do
703
841
  @surround_encoder = 'eac3'
704
842
  end
705
843
 
844
+ opts.on '--all-eac3' do
845
+ @surround_encoder = 'eac3'
846
+ @stereo_encoder = 'eac3'
847
+ end
848
+
849
+ opts.on '--keep-ac3-stereo' do
850
+ @keep_ac3_stereo = true
851
+ end
852
+
853
+ opts.on '--pass-dts' do
854
+ @pass_dts = true
855
+ end
856
+
706
857
  opts.on '--add-subtitle ARG' do |arg|
707
858
  if arg =~ /^([0-9]+)(?:=(forced))?$|^(auto)$|^([a-z]{3})$|^(.*)$/
708
859
  @subtitle_selections += [{
@@ -754,7 +905,13 @@ HERE
754
905
  @audio_selections.uniq!
755
906
  @subtitle_selections.uniq!
756
907
  @surround_bitrate = [[@surround_bitrate, 256].max, (@surround_encoder == 'ac3' ? 640 : 768)].min
757
- @stereo_bitrate = [[@stereo_bitrate, 128].max, 256].min
908
+ @stereo_bitrate = [[@stereo_bitrate, 128].max, (@stereo_encoder == 'eac3' ? 768 : 320)].min
909
+
910
+ if @mono_bitrate.nil?
911
+ @mono_bitrate = @stereo_bitrate / 2
912
+ else
913
+ @mono_bitrate = [[@mono_bitrate, 64].max, (@stereo_encoder == 'eac3' ? 768 : 256)].min
914
+ end
758
915
 
759
916
  [
760
917
  ['ffprobe', '-loglevel', 'quiet', '-version'],
@@ -764,7 +921,7 @@ HERE
764
921
  verify_tool_availability command
765
922
  end
766
923
 
767
- return if @detect
924
+ return if @scan or @detect
768
925
 
769
926
  encoders = find_encoders
770
927
 
@@ -799,6 +956,7 @@ HERE
799
956
  @target_1080p ||= (@hevc and @ten_bit) ? 6000 : 8000
800
957
  @target_720p ||= (@hevc and @ten_bit) ? 3000 : 4000
801
958
  @target_480p ||= (@hevc and @ten_bit) ? 1500 : 2000
959
+ @decode_method ||= @encoder =~ /nvenc$/ ? 'cuda' : 'auto'
802
960
 
803
961
  if @stereo_encoder.nil?
804
962
  if encoders =~ /aac_at/ or encoders =~ /libfdk_aac/
@@ -807,6 +965,11 @@ HERE
807
965
  @stereo_encoder = 'aac'
808
966
  end
809
967
  end
968
+
969
+ if @format == :mkv
970
+ capabilities = get_muxer_capabilities
971
+ @mkv_options = ['-default_mode', 'passthrough'] if capabilities =~ /passthrough/
972
+ end
810
973
  end
811
974
 
812
975
  def verify_tool_availability(command)
@@ -862,8 +1025,7 @@ HERE
862
1025
  ] + (encoder =~ /vaapi$/ ? ['-filter:v', 'format=nv12,hwupload'] : []) + [
863
1026
  '-c:v', encoder,
864
1027
  '-b:v', '1000k'
865
- ] + (encoder =~ /nvenc$/ ? ['-rc:v', 'vbr_hq', '-spatial-aq:v', '1'] : []) +
866
- (encoder == 'h264_nvenc' ? ['-temporal-aq:v', '1'] : []) +
1028
+ ] + (encoder =~ /nvenc$/ ? ['-rc:v', @nvenc_rc_mode] : []) +
867
1029
  (encoder == 'h264_qsv' ? ['-look_ahead:v', '1'] : []) +
868
1030
  (encoder == 'hevc_qsv' ? ['-load_plugin:v', 'hevc_hw'] : []) +
869
1031
  (encoder =~ /amf$/ ? ['-rc:v', 'vbr_latency'] : []) + [
@@ -884,23 +1046,51 @@ HERE
884
1046
  $CHILD_STATUS.exitstatus == 0
885
1047
  end
886
1048
 
1049
+ def get_muxer_capabilities
1050
+ Kernel.warn 'Getting muxer capabilities...'
1051
+ output = ''
1052
+
1053
+ begin
1054
+ IO.popen([
1055
+ 'ffmpeg',
1056
+ '-loglevel', 'quiet',
1057
+ '-h', 'muxer=matroska'
1058
+ ], :err=>[:child, :out]) do |io|
1059
+ io.each do |line|
1060
+ Kernel.warn line if @debug
1061
+ output += line
1062
+ end
1063
+ end
1064
+ rescue SystemCallError => e
1065
+ raise "getting muxer capabilities failed: #{e}"
1066
+ end
1067
+
1068
+ fail 'getting muxer capabilities failed' unless $CHILD_STATUS.exitstatus == 0
1069
+
1070
+ output
1071
+ end
1072
+
887
1073
  def process_input(path)
888
1074
  seconds = Time.now.tv_sec
889
1075
 
890
- unless @detect
891
- output_path = (@name.nil? ? File.basename(path, '.*') : File.basename(@name)) +
892
- '.' + @format.to_s
893
- fail "output file already exists: #{output_path}" if File.exist? output_path
1076
+ unless @scan or @detect
1077
+ output_path = File.basename(path, '.*') + '.' + @format.to_s
1078
+ fail_or_warn "output file already exists: #{output_path}" if File.exist? output_path
894
1079
 
895
1080
  log_path = output_path + '.log'
896
- fail "log file already exists: #{log_path}" if File.exist? log_path
1081
+ fail_or_warn "log file already exists: #{log_path}" if File.exist? log_path
897
1082
 
898
1083
  tmp_log_path = "_ffmpeg_#{rand(10000..99999)}_#{$PROCESS_ID}.#{@format.to_s}.log"
899
- fail "log file already exists: #{tmp_log_path}" if File.exist? tmp_log_path
1084
+ fail_or_warn "log file already exists: #{tmp_log_path}" if File.exist? tmp_log_path
900
1085
  end
901
1086
 
902
1087
  media_info = scan_media(path)
903
1088
 
1089
+ if @scan
1090
+ print_media_info media_info
1091
+ return
1092
+ end
1093
+
904
1094
  video, burn_subtitle = get_video_streams(media_info)
905
1095
  fail "video track not found: #{path}" if video.nil?
906
1096
 
@@ -911,7 +1101,7 @@ HERE
911
1101
  crop = detect_crop(media_info, video)
912
1102
 
913
1103
  if @detect
914
- present_crop(crop, path)
1104
+ present_crop crop, path
915
1105
  return
916
1106
  else
917
1107
  Kernel.warn "crop = #{crop[:width]}:#{crop[:height]}:#{crop[:x]}:#{crop[:y]}"
@@ -944,13 +1134,13 @@ HERE
944
1134
  '-stats'
945
1135
  ] + time_options +
946
1136
  decode_options + [
947
- '-i', "#{path}"
1137
+ '-i', path
948
1138
  ] + (@max_muxing_queue_size.nil? ? [] : ['-max_muxing_queue_size', @max_muxing_queue_size.to_s]) +
949
1139
  encode_options +
950
1140
  get_audio_options(media_info) +
951
1141
  get_subtitle_options(media_info, burn_subtitle) + [
952
1142
  '-metadata:g', 'title='
953
- ] + (@format == :mp4 ? ['-movflags', 'disable_chpl'] : []) + [
1143
+ ] + (@format == :mkv ? @mkv_options : ['-movflags', 'disable_chpl']) + [
954
1144
  output_path
955
1145
  ]
956
1146
 
@@ -995,17 +1185,25 @@ HERE
995
1185
  FileUtils.mv tmp_log_path, log_path
996
1186
  end
997
1187
 
998
- assemble_log(log_path, output)
1188
+ assemble_log log_path, output
999
1189
 
1000
1190
  if @format == :mp4
1001
1191
  Kernel.warn 'Done.'
1002
1192
  else
1003
- add_track_statistics_tags(output_path)
1193
+ add_track_statistics_tags output_path
1004
1194
  end
1005
1195
 
1006
1196
  Kernel.warn "\nElapsed time: #{seconds_to_time(Time.now.tv_sec - seconds)}\n\n"
1007
1197
  end
1008
1198
 
1199
+ def fail_or_warn(message)
1200
+ if @dry_run
1201
+ Kernel.warn "#{$PROGRAM_NAME}: #{message}"
1202
+ else
1203
+ fail message
1204
+ end
1205
+ end
1206
+
1009
1207
  def scan_media(path)
1010
1208
  Kernel.warn 'Scanning media...'
1011
1209
  output = ''
@@ -1040,6 +1238,93 @@ HERE
1040
1238
  media_info
1041
1239
  end
1042
1240
 
1241
+ def print_media_info(media_info)
1242
+ video = nil
1243
+ audio_streams = []
1244
+ subtitles = []
1245
+
1246
+ media_info['streams'].each do |stream|
1247
+ case stream['codec_type']
1248
+ when 'video'
1249
+ video = stream if video.nil?
1250
+ when 'audio'
1251
+ audio_streams += [stream]
1252
+ when 'subtitle'
1253
+ subtitles += [stream]
1254
+ end
1255
+ end
1256
+
1257
+ puts media_info['format']['filename']
1258
+ size = "#{video['width']} x #{video['height']}"
1259
+ print " format = #{video['codec_name']} / #{size} / #{video['avg_frame_rate']} fps"
1260
+ bitrate = get_bitrate(video)
1261
+ puts bitrate.nil? ? '' : " / #{bitrate} Kbps"
1262
+ duration = media_info['format']['duration'].to_f
1263
+ time = seconds_to_time(duration.to_i)
1264
+ milliseconds = duration.to_s.sub(/^[0-9]+(\.[0-9]+)$/, '\1')
1265
+ time += milliseconds unless milliseconds == '.0'
1266
+ puts " duration = #{time}"
1267
+ index = 0
1268
+
1269
+ audio_streams.each do |stream|
1270
+ index += 1
1271
+ puts "\##{index} audio:"
1272
+ codec_name = stream['codec_name']
1273
+ print " format = #{codec_name}"
1274
+
1275
+ if codec_name == 'dts'
1276
+ profile = stream.fetch('profile', 'DTS')
1277
+ print " (#{profile})" unless profile == 'DTS'
1278
+ end
1279
+
1280
+ print ' / '
1281
+ layout = stream.fetch('channel_layout', '')
1282
+
1283
+ if layout.empty?
1284
+ channels = stream['channels'].to_i
1285
+ print "#{channels} " + (channels > 1 ? 'channels' : 'channel')
1286
+ else
1287
+ print "#{layout}"
1288
+ end
1289
+
1290
+ bitrate = get_bitrate(stream)
1291
+ puts bitrate.nil? ? '' : " / #{bitrate} Kbps"
1292
+ puts " language = #{stream.fetch('tags', {}).fetch('language', '')}"
1293
+ title = stream.fetch('tags', {}).fetch('title', '')
1294
+ puts " title = #{title}" unless title.empty?
1295
+ end
1296
+
1297
+ index = 0
1298
+
1299
+ subtitles.each do |stream|
1300
+ index += 1
1301
+ puts "\##{index} subtitle:"
1302
+ print " format = #{stream['codec_name']}"
1303
+ frames = stream.fetch('tags', {}).fetch('NUMBER_OF_FRAMES-eng', '')
1304
+ puts frames.empty? ? '' : " / #{frames} " + (frames == 1 ? 'frame' : 'frames')
1305
+ puts " language = #{stream.fetch('tags', {}).fetch('language', '')}"
1306
+ title = stream.fetch('tags', {}).fetch('title', '')
1307
+ puts " title = #{title}" unless title.empty?
1308
+ default = (stream['disposition']['default'] == 1)
1309
+ forced = (stream['disposition']['forced'] == 1)
1310
+
1311
+ if default or forced
1312
+ puts ' flags = ' +
1313
+ (default ? 'default' : '') +
1314
+ ((default and forced) ? ' / ' : '') +
1315
+ (forced ? 'forced' : '')
1316
+ end
1317
+ end
1318
+ end
1319
+
1320
+ def get_bitrate(stream)
1321
+ bitrate = stream.fetch('bit_rate', '')
1322
+ bitrate = stream.fetch('tags', {}).fetch('BPS-eng', '') if bitrate.empty?
1323
+ return nil if bitrate.empty?
1324
+
1325
+ bitrate.to_i / 1000
1326
+ end
1327
+
1043
1328
  def detect_crop(media_info, video)
1044
1329
  Kernel.warn 'Detecting crop...'
1045
1330
  duration = media_info['format']['duration'].to_f
@@ -1162,10 +1447,10 @@ HERE
1162
1447
  drawbox_string = "#{crop[:x]}:#{crop[:y]}:#{crop[:width]}:#{crop[:height]}"
1163
1448
  puts
1164
1449
  puts escape_command([
1165
- 'mpv', '--no-audio', '--vf', "lavfi=[drawbox=#{drawbox_string}:invert:1]", path
1450
+ 'mpv', '--no-audio', "--vf=lavfi=[drawbox=#{drawbox_string}:invert:1]", path
1166
1451
  ])
1167
1452
  puts escape_command([
1168
- 'mpv', '--no-audio', '--vf', "crop=#{crop_string}", path
1453
+ 'mpv', '--no-audio', "--vf=crop=#{crop_string}", path
1169
1454
  ])
1170
1455
  puts
1171
1456
  puts escape_command([
@@ -1264,48 +1549,20 @@ HERE
1264
1549
  end
1265
1550
 
1266
1551
  def get_video_options(media_info, video, burn_subtitle, crop)
1267
- if @decoder_type == :cuvid
1268
- cuvid_decoder = case video['codec_name']
1269
- when 'mpeg1video'
1270
- 'mpeg1_cuvid'
1271
- when 'mpeg2video'
1272
- 'mpeg2_cuvid'
1273
- when 'mjpeg'
1274
- 'mjpeg_cuvid'
1275
- when 'mpeg4'
1276
- 'mpeg4_cuvid'
1277
- when 'h264'
1278
- 'h264_cuvid'
1279
- when 'vc1'
1280
- 'vc1_cuvid'
1281
- when 'vp8'
1282
- 'vp8_cuvid'
1283
- when 'vp9'
1284
- 'vp9_cuvid'
1285
- when 'hevc'
1286
- 'hevc_cuvid'
1287
- end
1288
- else
1289
- cuvid_decoder = nil
1290
- end
1291
-
1292
- cuvid_options = []
1293
-
1294
1552
  if burn_subtitle.nil?
1295
1553
  overlay_filter = nil
1296
1554
  else
1297
1555
  overlay_filter = "[0:#{burn_subtitle['index']}]overlay"
1298
- cuvid_decoder = nil
1299
1556
  end
1300
1557
 
1301
1558
  deinterlace = @deinterlace
1302
1559
  rate = @rate
1303
1560
 
1304
1561
  if @enable_filters
1305
- if video['avg_frame_rate'] == '30000/1001' or video['field_order'] != 'progressive'
1562
+ if video['avg_frame_rate'] == '30000/1001' or video.fetch('field_order', 'progressive') != 'progressive'
1306
1563
  deinterlace = true
1307
1564
 
1308
- if video['codec_name'] == 'mpeg2video'
1565
+ if video['codec_name'] == 'mpeg2video' and video['avg_frame_rate'] != '25/1'
1309
1566
  rate = '24000/1001'
1310
1567
  end
1311
1568
  end
@@ -1314,11 +1571,7 @@ HERE
1314
1571
  frame_rate_filter = nil
1315
1572
 
1316
1573
  if deinterlace
1317
- if cuvid_decoder.nil?
1318
- frame_rate_filter = 'yadif=deint=interlaced' unless @encoder == 'copy'
1319
- else
1320
- cuvid_options += ['-deint:v', 'adaptive']
1321
- end
1574
+ frame_rate_filter = 'yadif=deint=interlaced' unless @encoder == 'copy'
1322
1575
  end
1323
1576
 
1324
1577
  unless rate.nil?
@@ -1329,7 +1582,6 @@ HERE
1329
1582
 
1330
1583
  if @detelecine
1331
1584
  frame_rate_filter = 'fieldmatch=order=tff:combmatch=none,decimate'
1332
- cuvid_decoder = nil
1333
1585
  end
1334
1586
 
1335
1587
  width = video['width'].to_i
@@ -1344,21 +1596,9 @@ HERE
1344
1596
  if crop.nil? or (crop == {:width => width, :height => height, :x => 0, :y => 0})
1345
1597
  crop_filter = nil
1346
1598
  else
1347
- media_width = width
1348
- media_height = height
1349
- width = crop[:width]
1350
- height = crop[:height]
1351
-
1352
- if cuvid_decoder.nil?
1353
- crop_filter = "crop=#{width}:#{height}:#{crop[:x]}:#{crop[:y]}"
1354
- else
1355
- crop_filter = nil
1356
- top = crop[:y]
1357
- bottom = media_height - (top + height)
1358
- left = crop[:x]
1359
- right = media_width - (left + width)
1360
- cuvid_options += ['-crop:v', "#{top}x#{bottom}x#{left}x#{right}"]
1361
- end
1599
+ width = crop[:width]
1600
+ height = crop[:height]
1601
+ crop_filter = "crop=#{width}:#{height}:#{crop[:x]}:#{crop[:y]}"
1362
1602
  end
1363
1603
 
1364
1604
  if @hevc
@@ -1373,14 +1613,8 @@ HERE
1373
1613
  scale = [(max_width.to_f / width), (max_height.to_f / height)].min
1374
1614
  width = ((width * scale).ceil / 2) * 2
1375
1615
  height = ((height * scale).ceil / 2) * 2
1376
-
1377
- if cuvid_decoder.nil?
1378
- scale_filter = "scale=#{width}:#{height}"
1379
- scale_filter += ':flags=bicubic' unless overlay_filter.nil?
1380
- else
1381
- scale_filter = nil
1382
- cuvid_options += ['-resize:v', "#{width}x#{height}"]
1383
- end
1616
+ scale_filter = "scale=#{width}:#{height}"
1617
+ scale_filter += ':flags=bicubic' unless overlay_filter.nil?
1384
1618
  else
1385
1619
  scale_filter = nil
1386
1620
  end
@@ -1391,24 +1625,52 @@ HERE
1391
1625
  decode_options = []
1392
1626
  end
1393
1627
 
1394
- if cuvid_decoder.nil?
1395
- if (@decode_scope == :vc1 and video['codec_name'] == 'vc1') or @decode_scope == :all
1396
- if @encoder =~ /vaapi$/
1397
- decode_options = [
1398
- '-hwaccel', 'vaapi',
1399
- '-hwaccel_device', '/dev/dri/renderD128',
1400
- '-hwaccel_output_format', 'vaapi'
1401
- ]
1628
+ if (@decode_scope == :vc1 and video['codec_name'] == 'vc1') or @decode_scope == :all
1629
+ if @encoder =~ /vaapi$/
1630
+ decode_options = [
1631
+ '-hwaccel', 'vaapi',
1632
+ '-hwaccel_device', '/dev/dri/renderD128',
1633
+ '-hwaccel_output_format', 'vaapi'
1634
+ ]
1635
+ else
1636
+ if @decode_method == 'qsv' and @encoder != 'h264_qsv'
1637
+ decode_method = 'auto'
1402
1638
  else
1403
- decode_options += ['-hwaccel', 'auto']
1639
+ decode_method = @decode_method
1404
1640
  end
1405
- end
1406
- else
1407
- Kernel.warn "video decoder = #{cuvid_decoder}"
1408
1641
 
1409
- decode_options += [
1410
- '-c:v', cuvid_decoder
1411
- ] + cuvid_options
1642
+ decode_options += ['-hwaccel', decode_method]
1643
+
1644
+ if decode_method == 'qsv' and
1645
+ overlay_filter.nil? and
1646
+ frame_rate_filter.nil? and
1647
+ crop_filter.nil? and
1648
+ scale_filter.nil?
1649
+ qsv_decoder = case video['codec_name']
1650
+ when 'av1'
1651
+ 'av1_qsv'
1652
+ when 'h264'
1653
+ 'h264_qsv'
1654
+ when 'hevc'
1655
+ 'hevc_qsv'
1656
+ when 'mjpeg'
1657
+ 'mjpeg_qsv'
1658
+ when 'mpeg2video'
1659
+ 'mpeg2_qsv'
1660
+ when 'vc1'
1661
+ 'vc1_qsv'
1662
+ when 'vp8'
1663
+ 'vp8_qsv'
1664
+ when 'vp9'
1665
+ 'vp9_qsv'
1666
+ else
1667
+ nil
1668
+ end
1669
+
1670
+ decode_options += ['-qsv_device', @qsv_device] unless @qsv_device.nil?
1671
+ decode_options += ['-c:v', qsv_decoder] unless qsv_decoder.nil?
1672
+ end
1673
+ end
1412
1674
  end
1413
1675
 
1414
1676
  if @encoder =~ /vaapi$/ and not decode_options.include?('-hwaccel')
@@ -1460,15 +1722,19 @@ HERE
1460
1722
  if width > 1920 or height > 1080
1461
1723
  bitrate = @target_2160p
1462
1724
  max_bitrate = 40000
1725
+ max_dpb_mbs = 184320
1463
1726
  elsif width > 1280 or height > 720
1464
1727
  bitrate = @target_1080p
1465
1728
  max_bitrate = 20000
1729
+ max_dpb_mbs = 32768
1466
1730
  elsif width > 720 or height > 576
1467
1731
  bitrate = @target_720p
1468
1732
  max_bitrate = 10000
1733
+ max_dpb_mbs = 18000
1469
1734
  else
1470
1735
  bitrate = @target_480p
1471
1736
  max_bitrate = 5000
1737
+ max_dpb_mbs = 8100
1472
1738
 
1473
1739
  unless hdr
1474
1740
  color_primaries = pal ? 'bt470bg' : 'smpte170m'
@@ -1478,17 +1744,30 @@ HERE
1478
1744
 
1479
1745
  bitrate = @target unless @target.nil?
1480
1746
  bitrate = [bitrate, max_bitrate].min
1481
- maxrate = bitrate * 3
1747
+ maxrate = 0
1748
+ bufsize = 0
1482
1749
 
1483
- if @preset.nil? or @preset == 'none'
1484
- preset = nil
1485
- else
1750
+ if @encoder =~ /(nvenc|hevc_qsv|libx26[45])$/
1751
+ if @maxrate.nil?
1752
+ maxrate = bitrate * 3
1753
+ else
1754
+ maxrate = [[(bitrate * @maxrate).to_i, (bitrate * 1.5).to_i].max, bitrate * 3].min
1755
+ end
1756
+
1757
+ if @bufsize.nil?
1758
+ bufsize = maxrate if @encoder =~ /^libx26[45]$/
1759
+ else
1760
+ bufsize = [[(bitrate * @bufsize).to_i, bitrate].max, bitrate * 4].min
1761
+ end
1762
+ end
1763
+
1764
+ unless @preset.nil?
1486
1765
  valid = false
1487
1766
 
1488
1767
  case @encoder
1489
1768
  when /nvenc$/
1490
1769
  case @preset
1491
- when 'fast', 'medium', 'slow'
1770
+ when 'fast', 'medium', 'slow', /^p[1-7]$/
1492
1771
  valid = true
1493
1772
  end
1494
1773
  when /qsv$/
@@ -1505,7 +1784,6 @@ HERE
1505
1784
  end
1506
1785
 
1507
1786
  fail "invalid preset for encoder: #{@preset}" unless valid
1508
- preset = @preset
1509
1787
  end
1510
1788
 
1511
1789
  Kernel.warn 'Stream mapping:'
@@ -1513,7 +1791,7 @@ HERE
1513
1791
 
1514
1792
  unless @encoder == 'copy'
1515
1793
  text += " / #{bitrate} Kbps"
1516
- text += " / #{preset}" unless preset.nil?
1794
+ text += " / #{@preset}" unless @preset.nil?
1517
1795
  end
1518
1796
 
1519
1797
  unless burn_subtitle.nil?
@@ -1524,35 +1802,17 @@ HERE
1524
1802
  encode_options += ['-c:v', @encoder]
1525
1803
  encode_options += ['-pix_fmt:v', (@encoder =~ /(nvenc|qsv)$/ ? 'p010le' : 'yuv420p10le')] if @ten_bit
1526
1804
  encode_options += ['-b:v', "#{bitrate}k"] unless @encoder == 'copy'
1527
- encode_options += ['-maxrate:v', "#{maxrate}k"] if @encoder =~ /(nvenc|hevc_qsv|libx26[45])$/
1528
- encode_options += ['-bufsize:v', "#{maxrate}k"] if @encoder =~ /^libx26[45]$/
1529
- encode_options += ['-preset:v', preset] unless preset.nil?
1805
+ encode_options += ['-maxrate:v', "#{maxrate}k"] if maxrate > 0
1806
+ encode_options += ['-bufsize:v', "#{bufsize}k"] if bufsize > 0
1807
+ encode_options += ['-preset:v', @preset] unless @preset.nil?
1530
1808
  encode_options += ['-allow_sw:v', '1'] if @encoder =~ /videotoolbox$/ and @vt_allow_sw
1531
1809
 
1532
1810
  if @encoder =~ /nvenc$/
1533
- spatial_aq = @nvenc_spatial_aq.nil? ? false : @nvenc_spatial_aq
1534
- temporal_aq = @nvenc_temporal_aq.nil? ? false : @nvenc_temporal_aq
1535
-
1536
- if @hevc
1537
- spatial_aq_option = '-spatial_aq:v'
1538
- temporal_aq_option = '-temporal_aq:v'
1539
- else
1540
- spatial_aq_option = '-spatial-aq:v'
1541
- temporal_aq_option = '-temporal-aq:v'
1542
- end
1543
-
1544
- if @preset.nil?
1545
- encode_options += ['-rc:v', 'vbr_hq']
1546
- spatial_aq = true if @nvenc_spatial_aq.nil?
1547
-
1548
- unless @hevc
1549
- temporal_aq = true if @nvenc_temporal_aq.nil?
1550
- end
1551
- end
1552
-
1553
- encode_options += [spatial_aq_option, '1'] if spatial_aq
1554
- encode_options += [temporal_aq_option, '1'] if temporal_aq
1811
+ encode_options += ['-rc:v', @nvenc_rc_mode]
1812
+ encode_options += ['-spatial-aq:v', '1'] if @nvenc_spatial_aq
1813
+ encode_options += ['-temporal-aq:v', '1'] if @nvenc_temporal_aq
1555
1814
  encode_options += ['-rc-lookahead:v', @nvenc_lookahead.to_s] unless @nvenc_lookahead.nil?
1815
+ encode_options += ['-multipass:v', @nvenc_multipass] unless @nvenc_multipass.nil?
1556
1816
  encode_options += ['-refs:v', @nvenc_refs.to_s] unless @nvenc_refs.nil?
1557
1817
  encode_options += ['-bf:v', @nvenc_bframes.to_s] unless @nvenc_bframes.nil?
1558
1818
  end
@@ -1579,15 +1839,38 @@ HERE
1579
1839
 
1580
1840
  if @encoder == 'libx264'
1581
1841
  encode_options += ['-x264opts:v', 'ratetol=inf'] if @x264_avbr
1582
- encode_options += ['-mbtree:v', '0']
1842
+ encode_options += ['-mbtree:v', '0'] unless @x264_mbtree
1583
1843
 
1584
- if @preset.nil? and @x264_quick
1585
- encode_options += [
1586
- '-refs:v', '1',
1587
- '-rc-lookahead:v', '30',
1588
- '-partitions:v', 'none'
1589
- ]
1844
+ if @preset.nil?
1845
+ if @x264_quick
1846
+ encode_options += [
1847
+ '-refs:v', '1',
1848
+ '-rc-lookahead:v', '30',
1849
+ '-partitions:v', 'none'
1850
+ ]
1851
+ end
1852
+ else
1853
+ max_refs = [(max_dpb_mbs / (((width + 15) / 16) * ((height + 15) / 16))), 16].min
1854
+
1855
+ case @preset
1856
+ when 'slow'
1857
+ refs = 5
1858
+ when 'slower'
1859
+ refs = 8
1860
+ when 'veryslow', 'placebo'
1861
+ refs = 16
1862
+ else
1863
+ refs = 0
1864
+ end
1865
+
1866
+ encode_options += ['-refs:v', max_refs.to_s] if refs > max_refs
1590
1867
  end
1868
+
1869
+ encode_options += ['-x264-params:v', @x264_params] unless @x264_params.nil?
1870
+ end
1871
+
1872
+ if @encoder == 'libx265'
1873
+ encode_options += ['-x265-params:v', @x265_params] unless @x265_params.nil?
1591
1874
  end
1592
1875
 
1593
1876
  unless @ten_bit
@@ -1607,6 +1890,8 @@ HERE
1607
1890
  '-disposition:v', 'default'
1608
1891
  ]
1609
1892
 
1893
+ encode_options += ['-tag:v', 'hvc1'] if @format == :mp4 and @hevc
1894
+
1610
1895
  [decode_options, encode_options]
1611
1896
  end
1612
1897
 
@@ -1652,6 +1937,7 @@ HERE
1652
1937
  end
1653
1938
 
1654
1939
  width = selection[:width]
1940
+
1655
1941
  bitrate = case width
1656
1942
  when :stereo
1657
1943
  @stereo_bitrate
@@ -1733,8 +2019,12 @@ HERE
1733
2019
  if track[:width] == :original
1734
2020
  encoder = 'copy'
1735
2021
  else
2022
+ dts = (codec_name == 'dts' and track[:stream].fetch('profile', 'DTS') =~ /^DTS(?:-ES)?$/)
2023
+
1736
2024
  if track[:width] == :surround
1737
- if codec_name == @surround_encoder or codec_name == 'ac3'
2025
+ if codec_name == @surround_encoder or
2026
+ codec_name == 'ac3' or
2027
+ (@pass_dts and dts)
1738
2028
  encoder = 'copy'
1739
2029
  elsif input_channels > 2
1740
2030
  encoder = @surround_encoder
@@ -1743,9 +2033,10 @@ HERE
1743
2033
  end
1744
2034
 
1745
2035
  if encoder.nil?
1746
- if input_channels <= 2 and (codec_name == 'aac' or
2036
+ if input_channels <= 2 and (codec_name == 'aac' or
1747
2037
  ((codec_name == @surround_encoder or codec_name == 'ac3') and
1748
- (track[:stream]['bit_rate'].to_i / 1000) <= @stereo_bitrate))
2038
+ (@keep_ac3_stereo or (track[:stream]['bit_rate'].to_i / 1000) <= @stereo_bitrate)) or
2039
+ (@pass_dts and dts))
1749
2040
  encoder = 'copy'
1750
2041
  else
1751
2042
  encoder = @stereo_encoder
@@ -1754,7 +2045,7 @@ HERE
1754
2045
  if input_channels > 2
1755
2046
  channels = 2
1756
2047
  elsif input_channels == 1
1757
- bitrate = @stereo_bitrate / 2
2048
+ bitrate = @mono_bitrate
1758
2049
  end
1759
2050
  end
1760
2051
  end
@@ -1856,10 +2147,7 @@ HERE
1856
2147
  end
1857
2148
  end
1858
2149
 
1859
- unless force_subtitle.nil?
1860
- subtitles = [force_subtitle] + subtitles
1861
- end
1862
-
2150
+ subtitles = [force_subtitle] + subtitles unless force_subtitle.nil?
1863
2151
  subtitles.uniq!
1864
2152
  options = []
1865
2153
  index = 0
@@ -1876,7 +2164,7 @@ HERE
1876
2164
 
1877
2165
  options += [
1878
2166
  '-map', "0:#{subtitle['index']}",
1879
- "-c:s:#{index}", 'copy',
2167
+ "-c:s:#{index}", ((@format == :mp4 and subtitle['codec_name'] == 'subrip') ? 'mov_text' : 'copy'),
1880
2168
  "-disposition:s:#{index}", (force ? 'default+forced' : '0')
1881
2169
  ]
1882
2170