other_video_transcoding 0.1.1 → 0.4.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: a1982b8ee6d952b01d5c36833c741754ccd37508c0edc34a6b1de1b61daf9a21
4
- data.tar.gz: 82d4874af0e4b9d25487a9f49764f920750c18dc7c368d0b8fd06fb35bef5c97
3
+ metadata.gz: fa5db474ee387172ee779cd57befc925892dde23348ed6376cd35c416662576f
4
+ data.tar.gz: bd15276c43996afe54cf1bd7ad0f52eb55e5f5a6c1d90ebd36721d206eb17205
5
5
  SHA512:
6
- metadata.gz: aa06c1a7c65f63ff2b3e3ce93d25a9b50588cb7d938b1990100236b973fe832e367ae54fa8cd5d44a582d3e14e050d68ed2f9a5d14a1c4381c1314c4ddd07b5a
7
- data.tar.gz: 948c96268b59b5f09dba5314ceea8cbe9a47cbbe7a196128d2d266b2d7949c2a5620aa71eae759ffedd90a1c35bacf934fcfa8d585c04718d957d61418c0cf3b
6
+ metadata.gz: 577dcc59ee2b7b2304ad59243abd5999851ed5a0407934eccfd25e59d320145428b40a86eb3f6938b30e6c45d2343cc20aa2b62f474e7b4d0c1dd9a99d8dc43e
7
+ data.tar.gz: 053d07452a33c7d04239e8dee324ec954e08682607871cf8c79e2cdbf0cb6bbca0dff202e8464e2fe49f80c6e7a4adb50c3a9f815636e0fe786e7ac86829ddd6
@@ -2,6 +2,67 @@
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.4.0](https://github.com/donmelton/other_video_transcoding/releases/tag/0.4.0)
6
+
7
+ Sunday, November 1, 2020
8
+
9
+ * 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:
10
+ * 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.
11
+ * 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.
12
+ * 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.
13
+ * Add a `--nvenc-rc-mode` option to `other-transcode` for backward comaptibility with `ffmpeg` version 4.3.1 and older.
14
+ * 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.
15
+ * Deprecate the `--cuvid` option in `other-transcode` because the CUDA decoder is faster and more flexible.
16
+ * Deprecate `--preset none` in `other-transcode` because it's no longer necessary.
17
+ * Always use hyphen-based spellings of Nvidia AQ options in `ffmpeg` commands generated by `other-transcode`.
18
+ * Add `--x264-params` and `--x265-params` options to `other-transcode` for _very_ advanced manipulation of the `x264` and `x265` software encoders.
19
+ * 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.
20
+ * Update the link to Docker containers for Linux in the "README" document. Thanks, @ttyS0!
21
+
22
+ ## [0.3.2](https://github.com/donmelton/other_video_transcoding/releases/tag/0.3.2)
23
+
24
+ Friday, September 11, 2020
25
+
26
+ * 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.
27
+ * 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).
28
+ * 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).
29
+
30
+ ## [0.3.1](https://github.com/donmelton/other_video_transcoding/releases/tag/0.3.1)
31
+
32
+ Tuesday, May 26, 2020
33
+
34
+ * Modify the `--preview-crop` option in `other-transcode` to show commands compatible with newer versions of `mpv`.
35
+ * No longer force a NTSC film frame rate for interlaced inputs in PAL MPEG-2 format.
36
+ * When using the `--dry-run` option in `other-transcode`, issue a warning instead of failing if the output or log files already exist.
37
+ * Add a link to another Docker container for Linux in the "README" document. Thanks, @ttyS0!
38
+
39
+ ## [0.3.0](https://github.com/donmelton/other_video_transcoding/releases/tag/0.3.0)
40
+
41
+ Thursday, February 27, 2020
42
+
43
+ * 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).
44
+ * Add a `--mono-bitrate` option to `other-transcode`. This sets the mono audio bitrate, which is otherwise 50% of the stereo bitrate.
45
+ * 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.
46
+ * 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.
47
+ * 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.
48
+ * 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.
49
+ * 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.
50
+ * Add a `--x264-mbtree` option to `other-transcode`. This uses macroblock-tree ratecontrol and disables AVBR if in use.
51
+ * In order to ensure compatible H.264 levels, limit the number of reference frames when using the `x264` encoder with slower presets.
52
+ * Remove the deprecated `--name` option of `other-transcode`.
53
+ * Add a link to a Docker container for Linux in the "README" document. Thanks, @ttyS0!
54
+
55
+ ## [0.2.0](https://github.com/donmelton/other_video_transcoding/releases/tag/0.2.0)
56
+
57
+ Monday, January 13, 2020
58
+
59
+ * 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).
60
+ * 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).
61
+ * Add a `--copy-video` option to `other-transcode`. This disables transcoding and copies the original video track to the output.
62
+ * 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.
63
+ * 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.
64
+ * 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.
65
+
5
66
  ## [0.1.1](https://github.com/donmelton/other_video_transcoding/releases/tag/0.1.1)
6
67
 
7
68
  Friday, January 3, 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.1.1
18
+ <<-HERE
19
+ ask-ffmpeg-log 0.4.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.1.1
20
+ <<-HERE
21
+ other-transcode 0.4.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,56 +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
- --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
@@ -94,19 +93,20 @@ HERE
94
93
  --10-bit, --no-10-bit
95
94
  use 10-bit pixel format (default: not used for H.264,
96
95
  used for HEVC with Nvidia, Intel and x265 encoders)
97
- --preset NAME|none
98
- apply video encoder preset or disable default settings
96
+ --preset NAME apply video encoder preset
99
97
  --decode vc1|all|none
100
98
  set scope of automatic hardware decoder acceleration
101
99
  (default: vc1 for VC-1 format only)
102
- --cuvid use Nvidia video decoder
103
- for H.264, VC-1, MPEG-2 and other formats
104
- (ignores scope set by `--decode`)
105
- 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
+ HERE
106
106
  end
107
107
 
108
108
  def usage8
109
- <<HERE
109
+ <<-HERE
110
110
  --target [2160p=|1080p=|720p=|480p=]BITRATE
111
111
  set video bitrate target (default: based on input)
112
112
  or target for specific input resolution
@@ -114,11 +114,11 @@ HERE
114
114
  set video crop geometry (default: none)
115
115
  or automatically detect it
116
116
  --720p fit video within 1280x720 pixel bounds
117
- HERE
117
+ HERE
118
118
  end
119
119
 
120
120
  def usage9
121
- <<HERE
121
+ <<-HERE
122
122
  --1080p " " " 1920x1080 " "
123
123
  --deinterlace reduce interlace artifacts without changing frame rate
124
124
  (applied automatically for some inputs)
@@ -127,27 +127,34 @@ HERE
127
127
  --detelecine drop duplicate frames to restore original frame rate
128
128
  (disables any deinterlacing and forced frame rate)
129
129
  --no-filters disable any automatic adjustments via filters
130
- HERE
130
+ HERE
131
131
  end
132
132
 
133
133
  def usage10
134
- <<HERE
134
+ <<-HERE
135
+ --rc-maxrate FACTOR, --rc-bufsize FACTOR
136
+ set ratecontrol maximum rate and/or buffer size
137
+ as multiple of video bitrate target
138
+ --copy-video disable transcoding and copy original video track
135
139
 
136
140
  Apple Video Toolbox encoder options:
137
141
  --vt-allow-sw allow software encoding
138
142
 
139
143
  Nvidia video encoder options:
140
- --nvenc-spatial-aq, --no-nvenc-spatial-aq
141
- enable or disable spatial AQ (default: enabled)
142
- --nvenc-temporal-aq, --no-nvenc-temporal-aq
143
- enable or disable temporal AQ
144
- (default: enabled for H.264, disabled for HEVC)
144
+ --nvenc-spatial-aq
145
+ enable spatial adaptive quantization (AQ)
146
+ --nvenc-temporal-aq
147
+ enable temporal adaptive quantization (AQ)
145
148
  --nvenc-lookahead FRAMES
146
149
  set number of frames to look ahead for ratecontrol
150
+ --nvenc-multipass qres|fullres
151
+ set multipass encoding resolution
147
152
  --nvenc-refs FRAMES
148
153
  set number of reference frames
149
154
  --nvenc-bframes FRAMES
150
155
  set maximum number of B-frames
156
+ --nvenc-rc-mode vbr|vbr_hq
157
+ set ratecontrol mode (default: vbr)
151
158
 
152
159
  Intel Quick Sync video encoder options:
153
160
  --qsv-refs FRAMES
@@ -172,22 +179,42 @@ Video Acceleration API encoder options:
172
179
 
173
180
  x264 software video encoder options:
174
181
  --x264-avbr use average variable bitrate (AVBR) ratecontrol
182
+ --x264-mbtree use macroblock-tree ratecontrol (disables AVBR if in use)
175
183
  --x264-quick increase encoding speed by 70-80%
176
184
  with no easily perceptible loss in video quality
177
185
  (avoids quality problems with some encoder presets)
178
- HERE
186
+ --x264-params KEY=VALUE[:KEY=VALUE]...
187
+ override x264 configuration (disables other x264 options)
188
+
189
+ x265 software video encoder options:
190
+ --x265-params KEY=VALUE[:KEY=VALUE]...
191
+ override x265 configuration
192
+ HERE
179
193
  end
180
194
 
181
195
  def usage11
182
- <<HERE
196
+ <<-HERE
183
197
 
184
198
  Audio options:
185
199
  --main-audio TRACK[=WIDTH]
186
200
  select main audio track by number (default: 1)
187
201
  with optional width (default: surround)
188
- --add-audio TRACK|LANGUAGE|STRING[=WIDTH]
202
+ HERE
203
+ end
204
+
205
+ def usage12
206
+ <<-HERE
207
+ (use `original` to disable transcoding)
208
+ HERE
209
+ end
210
+
211
+ def usage13
212
+ <<-HERE
213
+ --add-audio TRACK|all|LANGUAGE|STRING[=WIDTH]
189
214
  add single audio track by number
190
215
  including main audio track
216
+ or all audio tracks
217
+ excluding main audio track
191
218
  or audio tracks by language code
192
219
  excluding main audio track
193
220
  (in ISO 639-2 format, e.g.: `eng`)
@@ -195,22 +222,61 @@ Audio options:
195
222
  excluding main audio track
196
223
  (comparison is case-insensitve)
197
224
  with optional width (default: stereo)
225
+ HERE
226
+ end
227
+
228
+ def usage14
229
+ <<-HERE
230
+ (use `original` to disable transcoding)
231
+ HERE
232
+ end
233
+
234
+ def usage15
235
+ <<-HERE
198
236
  --surround-bitrate BITRATE
199
237
  set surround audio bitrate (default: 640)
200
238
  --stereo-bitrate BITRATE
201
239
  set stereo audio bitrate (default: 256)
240
+ HERE
241
+ end
242
+
243
+ def usage16
244
+ <<-HERE
245
+ --mono-bitrate BITRATE
246
+ set mono audio bitrate (default: 50% of stereo bitrate)
247
+ HERE
248
+ end
249
+
250
+ def usage17
251
+ <<-HERE
202
252
  --eac3 use Enhanced AC-3 format for surround audio
253
+ HERE
254
+ end
255
+
256
+ def usage18
257
+ <<-HERE
258
+ --all-eac3 " " " " " all audio
259
+ --keep-ac3-stereo
260
+ copy stereo and mono audio in AC-3 format
261
+ even when orginal bitrate is above transcoding bitrate
262
+ --pass-dts enable passthrough of audio in DTS and DTS-ES formats
263
+ HERE
264
+ end
265
+
266
+ def usage19
267
+ <<-HERE
203
268
 
204
269
  Subtitle options:
205
- --add-subtitle TRACK[=forced]|auto|LANGUAGE|STRING
270
+ --add-subtitle TRACK[=forced]|auto|all|LANGUAGE|STRING
206
271
  add single subtitle track by number
207
272
  optionally setting forced disposition
208
273
  or enable automatic addition of forced subtitle
209
- or add subtitle tracks by language code
274
+ or add all subtitle tracks
275
+ or subtitle tracks by language code
210
276
  (in ISO 639-2 format, e.g.: `eng`)
211
277
  or subtitle tracks with titles containing string
212
278
  (comparison is case-insensitve)
213
- (all variations exclude any burned track)
279
+ (variations exclude any burned track)
214
280
  --burn-subtitle TRACK|auto
215
281
  burn subtitle track by number into video
216
282
  or enable automatic burning of forced subtitle
@@ -223,17 +289,18 @@ Other options:
223
289
  --version output version information and exit
224
290
 
225
291
  Requires `ffprobe`, `ffmpeg` and `mkvpropedit`.
226
- HERE
292
+ HERE
227
293
  end
228
294
 
229
295
  def initialize
230
296
  @position = nil
231
297
  @duration = nil
232
298
  @debug = false
299
+ @scan = false
233
300
  @detect = false
234
301
  @preview = false
235
302
  @format = :mkv
236
- @name = nil
303
+ @mkv_options = []
237
304
  @copy_track_names = false
238
305
  @max_muxing_queue_size = nil
239
306
  @dry_run = false
@@ -242,6 +309,7 @@ HERE
242
309
  @ten_bit = nil
243
310
  @preset = nil
244
311
  @decode_scope = :vc1
312
+ @decode_method = nil
245
313
  @decoder_type = nil
246
314
  @target_2160p = nil
247
315
  @target_1080p = nil
@@ -255,12 +323,16 @@ HERE
255
323
  @rate = nil
256
324
  @detelecine = false
257
325
  @enable_filters = true
326
+ @maxrate = nil
327
+ @bufsize = nil
258
328
  @vt_allow_sw = false
259
- @nvenc_spatial_aq = nil
260
- @nvenc_temporal_aq = nil
329
+ @nvenc_spatial_aq = false
330
+ @nvenc_temporal_aq = false
261
331
  @nvenc_lookahead = nil
332
+ @nvenc_multipass = nil
262
333
  @nvenc_refs = nil
263
334
  @nvenc_bframes = nil
335
+ @nvenc_rc_mode = 'vbr'
264
336
  @qsv_refs = nil
265
337
  @qsv_bframes = nil
266
338
  @amf_quality = nil
@@ -270,7 +342,10 @@ HERE
270
342
  @amf_bframes = nil
271
343
  @vaapi_compression = nil
272
344
  @x264_avbr = false
345
+ @x264_mbtree = false
273
346
  @x264_quick = false
347
+ @x264_params = nil
348
+ @x265_params = nil
274
349
  @audio_selections = [{
275
350
  :track => 1,
276
351
  :language => nil,
@@ -279,8 +354,11 @@ HERE
279
354
  }]
280
355
  @surround_bitrate = 640
281
356
  @stereo_bitrate = 256
357
+ @mono_bitrate = nil
282
358
  @surround_encoder = 'ac3'
283
359
  @stereo_encoder = nil
360
+ @keep_ac3_stereo = false
361
+ @pass_dts = false
284
362
  @subtitle_selections = []
285
363
  @auto_add_subtitle = false
286
364
  @burn_subtitle_track = 0
@@ -295,12 +373,16 @@ HERE
295
373
  case arg
296
374
  when 'full'
297
375
  puts usage1 + usage2 + usage3 + usage4 + usage5 + usage6 +
298
- usage7 + usage8 + usage9 + usage10 + usage11
376
+ usage7 + usage8 + usage9 + usage10 + usage11 + usage12 +
377
+ usage13 + usage14 + usage15 + usage16 + usage17 +
378
+ usage18 + usage19
299
379
  when 'more'
300
380
  puts usage1 + usage2 + usage3 + usage4 + usage6 + usage7 +
301
- usage8 + usage9 + usage11
381
+ usage8 + usage9 + usage11 + usage13 + usage15 + usage16 +
382
+ usage17 + usage18 + usage19
302
383
  else
303
- puts usage1 + usage3 + usage6 + usage8 + usage11
384
+ puts usage1 + usage3 + usage6 + usage8 + usage11 + usage13 +
385
+ usage15 + usage17 + usage19
304
386
  end
305
387
 
306
388
  exit
@@ -316,6 +398,7 @@ HERE
316
398
  end
317
399
 
318
400
  fail UsageError, 'missing argument' if ARGV.empty?
401
+
319
402
  configure ARGV.first
320
403
  ARGV.each { |arg| process_input arg }
321
404
  exit
@@ -344,6 +427,10 @@ HERE
344
427
  @debug = true
345
428
  end
346
429
 
430
+ opts.on '--scan' do
431
+ @scan = true
432
+ end
433
+
347
434
  opts.on '--preview-crop' do
348
435
  @detect = true
349
436
  @preview = true
@@ -358,10 +445,6 @@ HERE
358
445
  @format = :mp4
359
446
  end
360
447
 
361
- opts.on '--name ARG' do |arg|
362
- @name = arg
363
- end
364
-
365
448
  opts.on '--copy-track-names' do
366
449
  @copy_track_names = true
367
450
  end
@@ -411,10 +494,20 @@ HERE
411
494
 
412
495
  opts.on '--[no-]10-bit' do |arg|
413
496
  @ten_bit = arg
497
+ @encoder = nil if @encoder == 'copy'
414
498
  end
415
499
 
416
500
  opts.on '--preset ARG' do |arg|
417
- @preset = arg
501
+ if arg == 'none'
502
+ Kernel.warn '**********'
503
+ Kernel.warn 'Using deprecated `--preset` argument: none'
504
+ Kernel.warn '**********'
505
+ @preset = nil
506
+ else
507
+ @preset = arg
508
+ end
509
+
510
+ @encoder = nil if @encoder == 'copy'
418
511
  end
419
512
 
420
513
  opts.on '--decode ARG' do |arg|
@@ -426,7 +519,14 @@ HERE
426
519
  end
427
520
  end
428
521
 
522
+ opts.on '--[no-]cuda' do |arg|
523
+ @decode_method = arg ? 'cuda' : 'auto'
524
+ end
525
+
429
526
  opts.on '--cuvid' do
527
+ Kernel.warn '**********'
528
+ Kernel.warn 'Using deprecated option: --cuvid'
529
+ Kernel.warn '**********'
430
530
  @decoder_type = :cuvid
431
531
  end
432
532
 
@@ -451,6 +551,8 @@ HERE
451
551
  else
452
552
  @target = [arg.to_i, 1].max
453
553
  end
554
+
555
+ @encoder = nil if @encoder == 'copy'
454
556
  end
455
557
 
456
558
  opts.on '--crop ARG' do |arg|
@@ -462,22 +564,27 @@ HERE
462
564
  else
463
565
  fail UsageError, "invalid crop geometry: #{arg}"
464
566
  end
567
+
568
+ @encoder = nil if @encoder == 'copy'
465
569
  end
466
570
 
467
571
  opts.on '--720p' do
468
572
  @max_width = 1280
469
573
  @max_height = 720
574
+ @encoder = nil if @encoder == 'copy'
470
575
  end
471
576
 
472
577
  opts.on '--1080p' do
473
578
  @max_width = 1920
474
579
  @max_height = 1080
580
+ @encoder = nil if @encoder == 'copy'
475
581
  end
476
582
 
477
583
  opts.on '--deinterlace' do
478
584
  @deinterlace = true
479
585
  @detelecine = false
480
586
  @enable_filters = false
587
+ @encoder = nil if @encoder == 'copy' and @decoder_type != :cuvid
481
588
  end
482
589
 
483
590
  opts.on '--rate ARG' do |arg|
@@ -500,6 +607,7 @@ HERE
500
607
 
501
608
  @detelecine = false
502
609
  @enable_filters = false
610
+ @encoder = nil if @encoder == 'copy'
503
611
  end
504
612
 
505
613
  opts.on '--detelecine' do
@@ -507,23 +615,59 @@ HERE
507
615
  @deinterlace = false
508
616
  @rate = nil
509
617
  @enable_filters = false
618
+ @encoder = nil if @encoder == 'copy'
510
619
  end
511
620
 
512
621
  opts.on '--no-filters' do
513
622
  @enable_filters = false
514
623
  end
515
624
 
625
+ opts.on '--rc-maxrate ARG', Float do |arg|
626
+ @maxrate = arg
627
+ @encoder = nil if @encoder == 'copy'
628
+ end
629
+
630
+ opts.on '--rc-bufsize ARG', Float do |arg|
631
+ @bufsize = arg
632
+ @encoder = nil if @encoder == 'copy'
633
+ end
634
+
635
+ opts.on '--copy-video' do
636
+ @encoder = 'copy'
637
+ @hevc = false
638
+ @ten_bit = nil
639
+ @preset = nil
640
+ @target = nil
641
+ @crop = nil
642
+ @rate = nil
643
+ @detelecine = false
644
+ @enable_filters = false
645
+ @burn_subtitle_track = 0
646
+ end
647
+
516
648
  opts.on '--vt-allow-sw' do
517
649
  @encoder = @hevc ? 'hevc_videotoolbox' : 'h264_videotoolbox'
518
650
  @vt_allow_sw = true
519
651
  end
520
652
 
521
653
  opts.on '--[no-]nvenc-spatial-aq' do |arg|
654
+ unless arg
655
+ Kernel.warn '**********'
656
+ Kernel.warn 'Using deprecated option: --no-nvenc-spatial-aq'
657
+ Kernel.warn '**********'
658
+ end
659
+
522
660
  @encoder = @hevc ? 'hevc_nvenc' : 'h264_nvenc'
523
661
  @nvenc_spatial_aq = arg
524
662
  end
525
663
 
526
664
  opts.on '--[no-]nvenc-temporal-aq' do |arg|
665
+ unless arg
666
+ Kernel.warn '**********'
667
+ Kernel.warn 'Using deprecated option: --no-nvenc-temporal-aq'
668
+ Kernel.warn '**********'
669
+ end
670
+
527
671
  @encoder = @hevc ? 'hevc_nvenc' : 'h264_nvenc'
528
672
  @nvenc_temporal_aq = arg
529
673
  end
@@ -533,6 +677,17 @@ HERE
533
677
  @nvenc_lookahead = [[arg, 0].max, 32].min
534
678
  end
535
679
 
680
+ opts.on '--nvenc-multipass ARG' do |arg|
681
+ @encoder = @hevc ? 'hevc_nvenc' : 'h264_nvenc'
682
+
683
+ @nvenc_multipass = case arg
684
+ when 'qres', 'fullres'
685
+ arg
686
+ else
687
+ fail UsageError, "invalid multipass resolution argument: #{arg}"
688
+ end
689
+ end
690
+
536
691
  opts.on '--nvenc-refs ARG', Integer do |arg|
537
692
  @encoder = @hevc ? 'hevc_nvenc' : 'h264_nvenc'
538
693
  @nvenc_refs = [arg, 0].max
@@ -543,6 +698,17 @@ HERE
543
698
  @nvenc_bframes = [[arg, 0].max, 4].min
544
699
  end
545
700
 
701
+ opts.on '--nvenc-rc-mode ARG' do |arg|
702
+ @encoder = @hevc ? 'hevc_nvenc' : 'h264_nvenc'
703
+
704
+ @nvenc_rc_mode = case arg
705
+ when 'vbr', 'vbr_hq'
706
+ arg
707
+ else
708
+ fail UsageError, "invalid rate control argument: #{arg}"
709
+ end
710
+ end
711
+
546
712
  opts.on '--qsv-refs ARG', Integer do |arg|
547
713
  @encoder = @hevc ? 'hevc_qsv' : 'h264_qsv'
548
714
  @qsv_refs = [arg, 0].max
@@ -593,17 +759,51 @@ HERE
593
759
  @encoder = 'libx264'
594
760
  @hevc = false
595
761
  @x264_avbr = true
762
+ @x264_mbtree = false
763
+ @x264_params = nil
764
+ end
765
+
766
+ opts.on '--x264-mbtree' do
767
+ @encoder = 'libx264'
768
+ @hevc = false
769
+ @x264_mbtree = true
770
+ @x264_avbr = false
771
+ @x264_params = nil
596
772
  end
597
773
 
598
774
  opts.on '--x264-quick' do
599
775
  @encoder = 'libx264'
600
776
  @hevc = false
601
777
  @x264_quick = true
778
+ @x264_params = nil
602
779
  @preset = nil
603
780
  end
604
781
 
782
+ opts.on '--x264-params ARG' do |arg|
783
+ arg.split ':' do |param|
784
+ fail UsageError, "invalid argument: #{arg}" unless param =~ /^[\w\-]+=[\w\-\.,]+$/
785
+ end
786
+
787
+ @encoder = 'libx264'
788
+ @hevc = false
789
+ @x264_params = arg
790
+ @x264_avbr = false
791
+ @x264_mbtree = true
792
+ @x264_quick = false
793
+ end
794
+
795
+ opts.on '--x265-params ARG' do |arg|
796
+ arg.split ':' do |param|
797
+ fail UsageError, "invalid argument: #{arg}" unless param =~ /^[\w\-]+=[\w\-\.,]+$/
798
+ end
799
+
800
+ @encoder = 'libx265'
801
+ @hevc = true
802
+ @x265_params = arg
803
+ end
804
+
605
805
  opts.on '--main-audio ARG' do |arg|
606
- if arg =~ /^([0-9]+)(?:=(surround|stereo))?$/
806
+ if arg =~ /^([0-9]+)(?:=(stereo|surround|original))?$/
607
807
  @audio_selections[0][:track] = $1.to_i
608
808
  @audio_selections[0][:width] = $2.to_sym unless $2.nil?
609
809
  else
@@ -612,7 +812,7 @@ HERE
612
812
  end
613
813
 
614
814
  opts.on '--add-audio ARG' do |arg|
615
- if arg =~ /^([^=]+)(?:=(surround|stereo))?$/
815
+ if arg =~ /^([^=]+)(?:=(stereo|surround|original))?$/
616
816
  scope = $1
617
817
  width = $2
618
818
 
@@ -647,10 +847,27 @@ HERE
647
847
  @stereo_bitrate = arg
648
848
  end
649
849
 
850
+ opts.on '--mono-bitrate ARG', Integer do |arg|
851
+ @mono_bitrate = arg
852
+ end
853
+
650
854
  opts.on '--eac3' do
651
855
  @surround_encoder = 'eac3'
652
856
  end
653
857
 
858
+ opts.on '--all-eac3' do
859
+ @surround_encoder = 'eac3'
860
+ @stereo_encoder = 'eac3'
861
+ end
862
+
863
+ opts.on '--keep-ac3-stereo' do
864
+ @keep_ac3_stereo = true
865
+ end
866
+
867
+ opts.on '--pass-dts' do
868
+ @pass_dts = true
869
+ end
870
+
654
871
  opts.on '--add-subtitle ARG' do |arg|
655
872
  if arg =~ /^([0-9]+)(?:=(forced))?$|^(auto)$|^([a-z]{3})$|^(.*)$/
656
873
  @subtitle_selections += [{
@@ -676,6 +893,8 @@ HERE
676
893
  else
677
894
  fail UsageError, "invalid subtitle track: #{arg}"
678
895
  end
896
+
897
+ @encoder = nil if @encoder == 'copy'
679
898
  end
680
899
  end
681
900
 
@@ -700,7 +919,13 @@ HERE
700
919
  @audio_selections.uniq!
701
920
  @subtitle_selections.uniq!
702
921
  @surround_bitrate = [[@surround_bitrate, 256].max, (@surround_encoder == 'ac3' ? 640 : 768)].min
703
- @stereo_bitrate = [[@stereo_bitrate, 128].max, 256].min
922
+ @stereo_bitrate = [[@stereo_bitrate, 128].max, (@stereo_encoder == 'eac3' ? 768 : 320)].min
923
+
924
+ if @mono_bitrate.nil?
925
+ @mono_bitrate = @stereo_bitrate / 2
926
+ else
927
+ @mono_bitrate = [[@mono_bitrate, 64].max, (@stereo_encoder == 'eac3' ? 768 : 256)].min
928
+ end
704
929
 
705
930
  [
706
931
  ['ffprobe', '-loglevel', 'quiet', '-version'],
@@ -710,7 +935,7 @@ HERE
710
935
  verify_tool_availability command
711
936
  end
712
937
 
713
- return if @detect
938
+ return if @scan or @detect
714
939
 
715
940
  encoders = find_encoders
716
941
 
@@ -735,7 +960,7 @@ HERE
735
960
  else
736
961
  @encoder.sub!(/^h264/, 'hevc') if @hevc
737
962
 
738
- unless @dry_run or encoders =~ /#{@encoder}/
963
+ unless @dry_run or @encoder == 'copy' or encoders =~ /#{@encoder}/
739
964
  fail "video encoder not available: #{@encoder}"
740
965
  end
741
966
  end
@@ -745,6 +970,7 @@ HERE
745
970
  @target_1080p ||= (@hevc and @ten_bit) ? 6000 : 8000
746
971
  @target_720p ||= (@hevc and @ten_bit) ? 3000 : 4000
747
972
  @target_480p ||= (@hevc and @ten_bit) ? 1500 : 2000
973
+ @decode_method ||= @encoder =~ /nvenc$/ ? 'cuda' : 'auto'
748
974
 
749
975
  if @stereo_encoder.nil?
750
976
  if encoders =~ /aac_at/ or encoders =~ /libfdk_aac/
@@ -753,6 +979,11 @@ HERE
753
979
  @stereo_encoder = 'aac'
754
980
  end
755
981
  end
982
+
983
+ if @format == :mkv
984
+ capabilities = get_muxer_capabilities
985
+ @mkv_options = ['-default_mode', 'passthrough'] if capabilities =~ /passthrough/
986
+ end
756
987
  end
757
988
 
758
989
  def verify_tool_availability(command)
@@ -808,8 +1039,7 @@ HERE
808
1039
  ] + (encoder =~ /vaapi$/ ? ['-filter:v', 'format=nv12,hwupload'] : []) + [
809
1040
  '-c:v', encoder,
810
1041
  '-b:v', '1000k'
811
- ] + (encoder =~ /nvenc$/ ? ['-rc:v', 'vbr_hq', '-spatial-aq:v', '1'] : []) +
812
- (encoder == 'h264_nvenc' ? ['-temporal-aq:v', '1'] : []) +
1042
+ ] + (encoder =~ /nvenc$/ ? ['-rc:v', @nvenc_rc_mode] : []) +
813
1043
  (encoder == 'h264_qsv' ? ['-look_ahead:v', '1'] : []) +
814
1044
  (encoder == 'hevc_qsv' ? ['-load_plugin:v', 'hevc_hw'] : []) +
815
1045
  (encoder =~ /amf$/ ? ['-rc:v', 'vbr_latency'] : []) + [
@@ -830,23 +1060,51 @@ HERE
830
1060
  $CHILD_STATUS.exitstatus == 0
831
1061
  end
832
1062
 
1063
+ def get_muxer_capabilities
1064
+ Kernel.warn 'Getting muxer capabilities...'
1065
+ output = ''
1066
+
1067
+ begin
1068
+ IO.popen([
1069
+ 'ffmpeg',
1070
+ '-loglevel', 'quiet',
1071
+ '-h', 'muxer=matroska'
1072
+ ], :err=>[:child, :out]) do |io|
1073
+ io.each do |line|
1074
+ Kernel.warn line if @debug
1075
+ output += line
1076
+ end
1077
+ end
1078
+ rescue SystemCallError => e
1079
+ raise "getting muxer capabilities failed: #{e}"
1080
+ end
1081
+
1082
+ fail 'getting muxer capabilities failed' unless $CHILD_STATUS.exitstatus == 0
1083
+
1084
+ output
1085
+ end
1086
+
833
1087
  def process_input(path)
834
1088
  seconds = Time.now.tv_sec
835
1089
 
836
- unless @detect
837
- output_path = (@name.nil? ? File.basename(path, '.*') : File.basename(@name)) +
838
- '.' + @format.to_s
839
- fail "output file already exists: #{output_path}" if File.exist? output_path
1090
+ unless @scan or @detect
1091
+ output_path = File.basename(path, '.*') + '.' + @format.to_s
1092
+ fail_or_warn "output file already exists: #{output_path}" if File.exist? output_path
840
1093
 
841
1094
  log_path = output_path + '.log'
842
- fail "log file already exists: #{log_path}" if File.exist? log_path
1095
+ fail_or_warn "log file already exists: #{log_path}" if File.exist? log_path
843
1096
 
844
1097
  tmp_log_path = "_ffmpeg_#{rand(10000..99999)}_#{$PROCESS_ID}.#{@format.to_s}.log"
845
- fail "log file already exists: #{tmp_log_path}" if File.exist? tmp_log_path
1098
+ fail_or_warn "log file already exists: #{tmp_log_path}" if File.exist? tmp_log_path
846
1099
  end
847
1100
 
848
1101
  media_info = scan_media(path)
849
1102
 
1103
+ if @scan
1104
+ print_media_info media_info
1105
+ return
1106
+ end
1107
+
850
1108
  video, burn_subtitle = get_video_streams(media_info)
851
1109
  fail "video track not found: #{path}" if video.nil?
852
1110
 
@@ -857,7 +1115,7 @@ HERE
857
1115
  crop = detect_crop(media_info, video)
858
1116
 
859
1117
  if @detect
860
- present_crop(crop, path)
1118
+ present_crop crop, path
861
1119
  return
862
1120
  else
863
1121
  Kernel.warn "crop = #{crop[:width]}:#{crop[:height]}:#{crop[:x]}:#{crop[:y]}"
@@ -890,13 +1148,13 @@ HERE
890
1148
  '-stats'
891
1149
  ] + time_options +
892
1150
  decode_options + [
893
- '-i', "#{path}"
1151
+ '-i', path
894
1152
  ] + (@max_muxing_queue_size.nil? ? [] : ['-max_muxing_queue_size', @max_muxing_queue_size.to_s]) +
895
1153
  encode_options +
896
1154
  get_audio_options(media_info) +
897
1155
  get_subtitle_options(media_info, burn_subtitle) + [
898
1156
  '-metadata:g', 'title='
899
- ] + (@format == :mp4 ? ['-movflags', 'disable_chpl'] : []) + [
1157
+ ] + (@format == :mkv ? @mkv_options : ['-movflags', 'disable_chpl']) + [
900
1158
  output_path
901
1159
  ]
902
1160
 
@@ -941,17 +1199,25 @@ HERE
941
1199
  FileUtils.mv tmp_log_path, log_path
942
1200
  end
943
1201
 
944
- assemble_log(log_path, output)
1202
+ assemble_log log_path, output
945
1203
 
946
1204
  if @format == :mp4
947
1205
  Kernel.warn 'Done.'
948
1206
  else
949
- add_track_statistics_tags(output_path)
1207
+ add_track_statistics_tags output_path
950
1208
  end
951
1209
 
952
1210
  Kernel.warn "\nElapsed time: #{seconds_to_time(Time.now.tv_sec - seconds)}\n\n"
953
1211
  end
954
1212
 
1213
+ def fail_or_warn(message)
1214
+ if @dry_run
1215
+ Kernel.warn "#{$PROGRAM_NAME}: #{message}"
1216
+ else
1217
+ fail message
1218
+ end
1219
+ end
1220
+
955
1221
  def scan_media(path)
956
1222
  Kernel.warn 'Scanning media...'
957
1223
  output = ''
@@ -986,6 +1252,93 @@ HERE
986
1252
  media_info
987
1253
  end
988
1254
 
1255
+ def print_media_info(media_info)
1256
+ video = nil
1257
+ audio_streams = []
1258
+ subtitles = []
1259
+
1260
+ media_info['streams'].each do |stream|
1261
+ case stream['codec_type']
1262
+ when 'video'
1263
+ video = stream if video.nil?
1264
+ when 'audio'
1265
+ audio_streams += [stream]
1266
+ when 'subtitle'
1267
+ subtitles += [stream]
1268
+ end
1269
+ end
1270
+
1271
+ puts media_info['format']['filename']
1272
+ size = "#{video['width']} x #{video['height']}"
1273
+ print " format = #{video['codec_name']} / #{size} / #{video['avg_frame_rate']} fps"
1274
+ bitrate = get_bitrate(video)
1275
+ puts bitrate.nil? ? '' : " / #{bitrate} Kbps"
1276
+ duration = media_info['format']['duration'].to_f
1277
+ time = seconds_to_time(duration.to_i)
1278
+ milliseconds = duration.to_s.sub(/^[0-9]+(\.[0-9]+)$/, '\1')
1279
+ time += milliseconds unless milliseconds == '.0'
1280
+ puts " duration = #{time}"
1281
+ index = 0
1282
+
1283
+ audio_streams.each do |stream|
1284
+ index += 1
1285
+ puts "\##{index} audio:"
1286
+ codec_name = stream['codec_name']
1287
+ print " format = #{codec_name}"
1288
+
1289
+ if codec_name == 'dts'
1290
+ profile = stream.fetch('profile', 'DTS')
1291
+ print " (#{profile})" unless profile == 'DTS'
1292
+ end
1293
+
1294
+ print ' / '
1295
+ layout = stream.fetch('channel_layout', '')
1296
+
1297
+ if layout.empty?
1298
+ channels = stream['channels'].to_i
1299
+ print "#{channels} " + (channels > 1 ? 'channels' : 'channel')
1300
+ else
1301
+ print "#{layout}"
1302
+ end
1303
+
1304
+ bitrate = get_bitrate(stream)
1305
+ puts bitrate.nil? ? '' : " / #{bitrate} Kbps"
1306
+ puts " language = #{stream.fetch('tags', {}).fetch('language', '')}"
1307
+ title = stream.fetch('tags', {}).fetch('title', '')
1308
+ puts " title = #{title}" unless title.empty?
1309
+ end
1310
+
1311
+ index = 0
1312
+
1313
+ subtitles.each do |stream|
1314
+ index += 1
1315
+ puts "\##{index} subtitle:"
1316
+ print " format = #{stream['codec_name']}"
1317
+ frames = stream.fetch('tags', {}).fetch('NUMBER_OF_FRAMES-eng', '')
1318
+ puts frames.empty? ? '' : " / #{frames} " + (frames == 1 ? 'frame' : 'frames')
1319
+ puts " language = #{stream.fetch('tags', {}).fetch('language', '')}"
1320
+ title = stream.fetch('tags', {}).fetch('title', '')
1321
+ puts " title = #{title}" unless title.empty?
1322
+ default = (stream['disposition']['default'] == 1)
1323
+ forced = (stream['disposition']['forced'] == 1)
1324
+
1325
+ if default or forced
1326
+ puts ' flags = ' +
1327
+ (default ? 'default' : '') +
1328
+ ((default and forced) ? ' / ' : '') +
1329
+ (forced ? 'forced' : '')
1330
+ end
1331
+ end
1332
+ end
1333
+
1334
+ def get_bitrate(stream)
1335
+ bitrate = stream.fetch('bit_rate', '')
1336
+ bitrate = stream.fetch('tags', {}).fetch('BPS-eng', '') if bitrate.empty?
1337
+ return nil if bitrate.empty?
1338
+
1339
+ bitrate.to_i / 1000
1340
+ end
1341
+
989
1342
  def detect_crop(media_info, video)
990
1343
  Kernel.warn 'Detecting crop...'
991
1344
  duration = media_info['format']['duration'].to_f
@@ -1108,10 +1461,10 @@ HERE
1108
1461
  drawbox_string = "#{crop[:x]}:#{crop[:y]}:#{crop[:width]}:#{crop[:height]}"
1109
1462
  puts
1110
1463
  puts escape_command([
1111
- 'mpv', '--no-audio', '--vf', "lavfi=[drawbox=#{drawbox_string}:invert:1]", path
1464
+ 'mpv', '--no-audio', "--vf=lavfi=[drawbox=#{drawbox_string}:invert:1]", path
1112
1465
  ])
1113
1466
  puts escape_command([
1114
- 'mpv', '--no-audio', '--vf', "crop=#{crop_string}", path
1467
+ 'mpv', '--no-audio', "--vf=crop=#{crop_string}", path
1115
1468
  ])
1116
1469
  puts
1117
1470
  puts escape_command([
@@ -1241,23 +1594,17 @@ HERE
1241
1594
  overlay_filter = nil
1242
1595
  else
1243
1596
  overlay_filter = "[0:#{burn_subtitle['index']}]overlay"
1244
-
1245
- unless cuvid_decoder.nil?
1246
- Kernel.warn '**********'
1247
- Kernel.warn "burning subtitle disables video decoder: #{cuvid_decoder}"
1248
- Kernel.warn '**********'
1249
- cuvid_decoder = nil
1250
- end
1597
+ cuvid_decoder = nil
1251
1598
  end
1252
1599
 
1253
1600
  deinterlace = @deinterlace
1254
1601
  rate = @rate
1255
1602
 
1256
1603
  if @enable_filters
1257
- if video['avg_frame_rate'] == '30000/1001' or video['field_order'] != 'progressive'
1604
+ if video['avg_frame_rate'] == '30000/1001' or video.fetch('field_order', 'progressive') != 'progressive'
1258
1605
  deinterlace = true
1259
1606
 
1260
- if video['codec_name'] == 'mpeg2video'
1607
+ if video['codec_name'] == 'mpeg2video' and video['avg_frame_rate'] != '25/1'
1261
1608
  rate = '24000/1001'
1262
1609
  end
1263
1610
  end
@@ -1267,7 +1614,7 @@ HERE
1267
1614
 
1268
1615
  if deinterlace
1269
1616
  if cuvid_decoder.nil?
1270
- frame_rate_filter = 'yadif=deint=interlaced'
1617
+ frame_rate_filter = 'yadif=deint=interlaced' unless @encoder == 'copy'
1271
1618
  else
1272
1619
  cuvid_options += ['-deint:v', 'adaptive']
1273
1620
  end
@@ -1280,14 +1627,8 @@ HERE
1280
1627
  end
1281
1628
 
1282
1629
  if @detelecine
1283
- unless cuvid_decoder.nil?
1284
- Kernel.warn '**********'
1285
- Kernel.warn "detelecine disables video decoder: #{cuvid_decoder}"
1286
- Kernel.warn '**********'
1287
- cuvid_decoder = nil
1288
- end
1289
-
1290
1630
  frame_rate_filter = 'fieldmatch=order=tff:combmatch=none,decimate'
1631
+ cuvid_decoder = nil
1291
1632
  end
1292
1633
 
1293
1634
  width = video['width'].to_i
@@ -1358,7 +1699,7 @@ HERE
1358
1699
  '-hwaccel_output_format', 'vaapi'
1359
1700
  ]
1360
1701
  else
1361
- decode_options += ['-hwaccel', 'auto']
1702
+ decode_options += ['-hwaccel', @decode_method]
1362
1703
  end
1363
1704
  end
1364
1705
  else
@@ -1375,12 +1716,16 @@ HERE
1375
1716
  conversion_filter = nil
1376
1717
  end
1377
1718
 
1378
- filter = overlay_filter.nil? ? '' : overlay_filter
1379
- filter += frame_rate_filter.nil? ? '' : ",#{frame_rate_filter}"
1380
- filter += crop_filter.nil? ? '' : ",#{crop_filter}"
1381
- filter += scale_filter.nil? ? '' : ",#{scale_filter}"
1382
- filter += conversion_filter.nil? ? '' : ",#{conversion_filter}"
1383
- filter.sub!(/^,/, '')
1719
+ if @encoder == 'copy'
1720
+ filter = ''
1721
+ else
1722
+ filter = overlay_filter.nil? ? '' : overlay_filter
1723
+ filter += frame_rate_filter.nil? ? '' : ",#{frame_rate_filter}"
1724
+ filter += crop_filter.nil? ? '' : ",#{crop_filter}"
1725
+ filter += scale_filter.nil? ? '' : ",#{scale_filter}"
1726
+ filter += conversion_filter.nil? ? '' : ",#{conversion_filter}"
1727
+ filter.sub!(/^,/, '')
1728
+ end
1384
1729
 
1385
1730
  if overlay_filter.nil?
1386
1731
  encode_options = [
@@ -1414,15 +1759,19 @@ HERE
1414
1759
  if width > 1920 or height > 1080
1415
1760
  bitrate = @target_2160p
1416
1761
  max_bitrate = 40000
1762
+ max_dpb_mbs = 184320
1417
1763
  elsif width > 1280 or height > 720
1418
1764
  bitrate = @target_1080p
1419
1765
  max_bitrate = 20000
1766
+ max_dpb_mbs = 32768
1420
1767
  elsif width > 720 or height > 576
1421
1768
  bitrate = @target_720p
1422
1769
  max_bitrate = 10000
1770
+ max_dpb_mbs = 18000
1423
1771
  else
1424
1772
  bitrate = @target_480p
1425
1773
  max_bitrate = 5000
1774
+ max_dpb_mbs = 8100
1426
1775
 
1427
1776
  unless hdr
1428
1777
  color_primaries = pal ? 'bt470bg' : 'smpte170m'
@@ -1432,17 +1781,30 @@ HERE
1432
1781
 
1433
1782
  bitrate = @target unless @target.nil?
1434
1783
  bitrate = [bitrate, max_bitrate].min
1435
- maxrate = bitrate * 3
1784
+ maxrate = 0
1785
+ bufsize = 0
1436
1786
 
1437
- if @preset.nil? or @preset == 'none'
1438
- preset = nil
1439
- else
1787
+ if @encoder =~ /(nvenc|hevc_qsv|libx26[45])$/
1788
+ if @maxrate.nil?
1789
+ maxrate = bitrate * 3
1790
+ else
1791
+ maxrate = [[(bitrate * @maxrate).to_i, (bitrate * 1.5).to_i].max, bitrate * 3].min
1792
+ end
1793
+
1794
+ if @bufsize.nil?
1795
+ bufsize = maxrate if @encoder =~ /^libx26[45]$/
1796
+ else
1797
+ bufsize = [[(bitrate * @bufsize).to_i, bitrate].max, bitrate * 4].min
1798
+ end
1799
+ end
1800
+
1801
+ unless @preset.nil?
1440
1802
  valid = false
1441
1803
 
1442
1804
  case @encoder
1443
1805
  when /nvenc$/
1444
1806
  case @preset
1445
- when 'fast', 'medium', 'slow'
1807
+ when 'fast', 'medium', 'slow', /^p[1-7]$/
1446
1808
  valid = true
1447
1809
  end
1448
1810
  when /qsv$/
@@ -1459,12 +1821,15 @@ HERE
1459
1821
  end
1460
1822
 
1461
1823
  fail "invalid preset for encoder: #{@preset}" unless valid
1462
- preset = @preset
1463
1824
  end
1464
1825
 
1465
1826
  Kernel.warn 'Stream mapping:'
1466
- text = "#{sprintf("%2d", video['index'])} = #{@encoder} / #{bitrate} Kbps"
1467
- text += " / #{preset}" unless preset.nil?
1827
+ text = "#{sprintf("%2d", video['index'])} = #{@encoder}"
1828
+
1829
+ unless @encoder == 'copy'
1830
+ text += " / #{bitrate} Kbps"
1831
+ text += " / #{@preset}" unless @preset.nil?
1832
+ end
1468
1833
 
1469
1834
  unless burn_subtitle.nil?
1470
1835
  text += " / #{sprintf("%d", burn_subtitle['index'])} = #{burn_subtitle['codec_name']} / burn"
@@ -1473,36 +1838,18 @@ HERE
1473
1838
  Kernel.warn text
1474
1839
  encode_options += ['-c:v', @encoder]
1475
1840
  encode_options += ['-pix_fmt:v', (@encoder =~ /(nvenc|qsv)$/ ? 'p010le' : 'yuv420p10le')] if @ten_bit
1476
- encode_options += ['-b:v', "#{bitrate}k"]
1477
- encode_options += ['-maxrate:v', "#{maxrate}k"] if @encoder =~ /(nvenc|hevc_qsv|libx26[45])$/
1478
- encode_options += ['-bufsize:v', "#{maxrate}k"] if @encoder =~ /^libx26[45]$/
1479
- encode_options += ['-preset:v', preset] unless preset.nil?
1841
+ encode_options += ['-b:v', "#{bitrate}k"] unless @encoder == 'copy'
1842
+ encode_options += ['-maxrate:v', "#{maxrate}k"] if maxrate > 0
1843
+ encode_options += ['-bufsize:v', "#{bufsize}k"] if bufsize > 0
1844
+ encode_options += ['-preset:v', @preset] unless @preset.nil?
1480
1845
  encode_options += ['-allow_sw:v', '1'] if @encoder =~ /videotoolbox$/ and @vt_allow_sw
1481
1846
 
1482
1847
  if @encoder =~ /nvenc$/
1483
- spatial_aq = @nvenc_spatial_aq.nil? ? false : @nvenc_spatial_aq
1484
- temporal_aq = @nvenc_temporal_aq.nil? ? false : @nvenc_temporal_aq
1485
-
1486
- if @hevc
1487
- spatial_aq_option = '-spatial_aq:v'
1488
- temporal_aq_option = '-temporal_aq:v'
1489
- else
1490
- spatial_aq_option = '-spatial-aq:v'
1491
- temporal_aq_option = '-temporal-aq:v'
1492
- end
1493
-
1494
- if @preset.nil?
1495
- encode_options += ['-rc:v', 'vbr_hq']
1496
- spatial_aq = true if @nvenc_spatial_aq.nil?
1497
-
1498
- unless @hevc
1499
- temporal_aq = true if @nvenc_temporal_aq.nil?
1500
- end
1501
- end
1502
-
1503
- encode_options += [spatial_aq_option, '1'] if spatial_aq
1504
- encode_options += [temporal_aq_option, '1'] if temporal_aq
1848
+ encode_options += ['-rc:v', @nvenc_rc_mode]
1849
+ encode_options += ['-spatial-aq:v', '1'] if @nvenc_spatial_aq
1850
+ encode_options += ['-temporal-aq:v', '1'] if @nvenc_temporal_aq
1505
1851
  encode_options += ['-rc-lookahead:v', @nvenc_lookahead.to_s] unless @nvenc_lookahead.nil?
1852
+ encode_options += ['-multipass:v', @nvenc_multipass] unless @nvenc_multipass.nil?
1506
1853
  encode_options += ['-refs:v', @nvenc_refs.to_s] unless @nvenc_refs.nil?
1507
1854
  encode_options += ['-bf:v', @nvenc_bframes.to_s] unless @nvenc_bframes.nil?
1508
1855
  end
@@ -1529,29 +1876,59 @@ HERE
1529
1876
 
1530
1877
  if @encoder == 'libx264'
1531
1878
  encode_options += ['-x264opts:v', 'ratetol=inf'] if @x264_avbr
1532
- encode_options += ['-mbtree:v', '0']
1879
+ encode_options += ['-mbtree:v', '0'] unless @x264_mbtree
1533
1880
 
1534
- if @preset.nil? and @x264_quick
1535
- encode_options += [
1536
- '-refs:v', '1',
1537
- '-rc-lookahead:v', '30',
1538
- '-partitions:v', 'none'
1539
- ]
1881
+ if @preset.nil?
1882
+ if @x264_quick
1883
+ encode_options += [
1884
+ '-refs:v', '1',
1885
+ '-rc-lookahead:v', '30',
1886
+ '-partitions:v', 'none'
1887
+ ]
1888
+ end
1889
+ else
1890
+ max_refs = [(max_dpb_mbs / (((width + 15) / 16) * ((height + 15) / 16))), 16].min
1891
+
1892
+ case @preset
1893
+ when 'slow'
1894
+ refs = 5
1895
+ when 'slower'
1896
+ refs = 8
1897
+ when 'veryslow', 'placebo'
1898
+ refs = 16
1899
+ else
1900
+ refs = 0
1901
+ end
1902
+
1903
+ encode_options += ['-refs:v', max_refs.to_s] if refs > max_refs
1540
1904
  end
1905
+
1906
+ encode_options += ['-x264-params:v', @x264_params] unless @x264_params.nil?
1907
+ end
1908
+
1909
+ if @encoder == 'libx265'
1910
+ encode_options += ['-x265-params:v', @x265_params] unless @x265_params.nil?
1541
1911
  end
1542
1912
 
1543
1913
  unless @ten_bit
1544
1914
  encode_options += ['-profile:v', 'high'] if @encoder =~ /^(h264_nvenc|h264_amf|libx264)$/
1545
1915
  end
1546
1916
 
1917
+ unless @encoder == 'copy'
1918
+ encode_options += [
1919
+ '-color_primaries:v', color_primaries,
1920
+ '-color_trc:v', color_trc,
1921
+ '-colorspace:v', colorspace
1922
+ ]
1923
+ end
1924
+
1547
1925
  encode_options += [
1548
- '-color_primaries:v', color_primaries,
1549
- '-color_trc:v', color_trc,
1550
- '-colorspace:v', colorspace,
1551
1926
  '-metadata:s:v', 'title=',
1552
1927
  '-disposition:v', 'default'
1553
1928
  ]
1554
1929
 
1930
+ encode_options += ['-tag:v', 'hvc1'] if @format == :mp4 and @hevc
1931
+
1555
1932
  [decode_options, encode_options]
1556
1933
  end
1557
1934
 
@@ -1577,7 +1954,14 @@ HERE
1577
1954
  audio_tracks = [{
1578
1955
  :stream => main_audio,
1579
1956
  :width => width,
1580
- :bitrate => width == :surround ? @surround_bitrate : @stereo_bitrate
1957
+ :bitrate => case width
1958
+ when :stereo
1959
+ @stereo_bitrate
1960
+ when :surround
1961
+ @surround_bitrate
1962
+ when :original
1963
+ nil
1964
+ end
1581
1965
  }]
1582
1966
 
1583
1967
  titles = {}
@@ -1590,7 +1974,15 @@ HERE
1590
1974
  end
1591
1975
 
1592
1976
  width = selection[:width]
1593
- bitrate = width == :surround ? @surround_bitrate : @stereo_bitrate
1977
+
1978
+ bitrate = case width
1979
+ when :stereo
1980
+ @stereo_bitrate
1981
+ when :surround
1982
+ @surround_bitrate
1983
+ when :original
1984
+ nil
1985
+ end
1594
1986
 
1595
1987
  unless selection[:track].nil?
1596
1988
  audio_track = 0
@@ -1616,7 +2008,8 @@ HERE
1616
2008
  media_info['streams'].each do |stream|
1617
2009
  next if stream['codec_type'] != 'audio'
1618
2010
 
1619
- if stream.fetch('tags', {}).fetch('language', '') == selection[:language] and
2011
+ if (selection[:language] == 'all' or
2012
+ stream.fetch('tags', {}).fetch('language', '') == selection[:language]) and
1620
2013
  stream['index'] != main_audio['index']
1621
2014
  audio_tracks += [{
1622
2015
  :stream => stream,
@@ -1660,28 +2053,37 @@ HERE
1660
2053
  bitrate = nil
1661
2054
  channels = nil
1662
2055
 
1663
- if track[:width] == :surround
1664
- if codec_name == @surround_encoder or codec_name == 'ac3'
2056
+ if track[:width] == :original
1665
2057
  encoder = 'copy'
1666
- elsif input_channels > 2
1667
- encoder = @surround_encoder
1668
- bitrate = @surround_bitrate
2058
+ else
2059
+ dts = (codec_name == 'dts' and track[:stream].fetch('profile', 'DTS') =~ /^DTS(?:-ES)?$/)
2060
+
2061
+ if track[:width] == :surround
2062
+ if codec_name == @surround_encoder or
2063
+ codec_name == 'ac3' or
2064
+ (@pass_dts and dts)
2065
+ encoder = 'copy'
2066
+ elsif input_channels > 2
2067
+ encoder = @surround_encoder
2068
+ bitrate = @surround_bitrate
2069
+ end
1669
2070
  end
1670
- end
1671
2071
 
1672
- if encoder.nil?
1673
- if input_channels <= 2 and (codec_name == 'aac' or
1674
- ((codec_name == @surround_encoder or codec_name == 'ac3') and
1675
- (track[:stream]['bit_rate'].to_i / 1000) <= @stereo_bitrate))
1676
- encoder = 'copy'
1677
- else
1678
- encoder = @stereo_encoder
1679
- bitrate = @stereo_bitrate
2072
+ if encoder.nil?
2073
+ if input_channels <= 2 and (codec_name == 'aac' or
2074
+ ((codec_name == @surround_encoder or codec_name == 'ac3') and
2075
+ (@keep_ac3_stereo or (track[:stream]['bit_rate'].to_i / 1000) <= @stereo_bitrate)) or
2076
+ (@pass_dts and dts))
2077
+ encoder = 'copy'
2078
+ else
2079
+ encoder = @stereo_encoder
2080
+ bitrate = @stereo_bitrate
1680
2081
 
1681
- if input_channels > 2
1682
- channels = 2
1683
- elsif input_channels == 1
1684
- bitrate = @stereo_bitrate / 2
2082
+ if input_channels > 2
2083
+ channels = 2
2084
+ elsif input_channels == 1
2085
+ bitrate = @mono_bitrate
2086
+ end
1685
2087
  end
1686
2088
  end
1687
2089
  end
@@ -1764,7 +2166,8 @@ HERE
1764
2166
  media_info['streams'].each do |stream|
1765
2167
  next if stream['codec_type'] != 'subtitle'
1766
2168
 
1767
- if stream.fetch('tags', {}).fetch('language', '') == selection[:language]
2169
+ if (selection[:language] == 'all' or
2170
+ stream.fetch('tags', {}).fetch('language', '') == selection[:language])
1768
2171
  subtitles += [stream]
1769
2172
  end
1770
2173
  end
@@ -1781,10 +2184,7 @@ HERE
1781
2184
  end
1782
2185
  end
1783
2186
 
1784
- unless force_subtitle.nil?
1785
- subtitles = [force_subtitle] + subtitles
1786
- end
1787
-
2187
+ subtitles = [force_subtitle] + subtitles unless force_subtitle.nil?
1788
2188
  subtitles.uniq!
1789
2189
  options = []
1790
2190
  index = 0
@@ -1792,9 +2192,6 @@ HERE
1792
2192
  subtitles.each do |subtitle|
1793
2193
  next if (not burn_subtitle.nil?) and burn_subtitle['index'] == subtitle['index']
1794
2194
 
1795
- next if @format == :mp4 and
1796
- (subtitle['codec_name'] == 'hdmv_pgs_subtitle' or subtitle['codec_name'] == 'dvd_subtitle')
1797
-
1798
2195
  force = (index == 0 and not force_subtitle.nil?)
1799
2196
  text = "#{sprintf("%2d", subtitle['index'])} = #{subtitle['codec_name']}"
1800
2197
  text += ' / force' if force
@@ -1804,7 +2201,7 @@ HERE
1804
2201
 
1805
2202
  options += [
1806
2203
  '-map', "0:#{subtitle['index']}",
1807
- "-c:s:#{index}", 'copy',
2204
+ "-c:s:#{index}", ((@format == :mp4 and subtitle['codec_name'] == 'subrip') ? 'mov_text' : 'copy'),
1808
2205
  "-disposition:s:#{index}", (force ? 'default+forced' : '0')
1809
2206
  ]
1810
2207