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