other_video_transcoding 0.1.0 → 0.3.2

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