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 +4 -4
- data/CHANGELOG.md +56 -0
- data/LICENSE +1 -1
- data/README.md +21 -1
- data/bin/ask-ffmpeg-log +13 -9
- data/bin/other-transcode +453 -128
- 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.gemspec +1 -1
- metadata +11 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cfd039fdab5dca779448614baaf5f0e99b3d7dc883f97693919a016224e4b7aa
|
|
4
|
+
data.tar.gz: c97d8899ea867a018059d1896c3608e3982f8677f8fe81c7506097171c7591e8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1915b0bdacf95a0bdfe5e825497f9081571318aaf9423a10df614b0f5ab7a74949ebd6c6039c4ef09c5ce2d567dbe6a851019f996d64284a1ab0525a0a7c10e2
|
|
7
|
+
data.tar.gz: 64f23ade8dc74a15f8024313b66cd91b3298e80d4e39be391f47630ddd2aa812c67271bfa522794202dd33b4ce18b601c8cbf77a8b46078f288c050afd5eef3a
|
data/CHANGELOG.md
CHANGED
|
@@ -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
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
|
|
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:
|
data/bin/ask-ffmpeg-log
CHANGED
|
@@ -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
|
-
|
|
19
|
-
ask-ffmpeg-log 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
|
-
|
|
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}
|
|
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
|
data/bin/other-transcode
CHANGED
|
@@ -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
|
-
|
|
21
|
-
other-transcode 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
|
-
|
|
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
|
-
|
|
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
|
-
--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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
(
|
|
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
|
-
@
|
|
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}
|
|
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|
|
|
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|
|
|
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,
|
|
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 =
|
|
837
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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',
|
|
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 == :
|
|
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
|
|
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
|
|
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',
|
|
1374
|
+
'mpv', '--no-audio', "--vf=lavfi=[drawbox=#{drawbox_string}:invert:1]", path
|
|
1110
1375
|
])
|
|
1111
1376
|
puts escape_command([
|
|
1112
|
-
'mpv', '--no-audio',
|
|
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
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
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 =
|
|
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}
|
|
1465
|
-
|
|
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
|
|
1476
|
-
encode_options += ['-bufsize:v', "#{
|
|
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?
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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] == :
|
|
1662
|
-
if codec_name == @surround_encoder or codec_name == 'ac3'
|
|
1982
|
+
if track[:width] == :original
|
|
1663
1983
|
encoder = 'copy'
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
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
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
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
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
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
|
|
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
|
|