diff --git a/README.md b/README.md index df0bd64..0a4ab81 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ It also simplifies some common tasks such as converting files by wrapping comple For example, to convert a file to H.265/HEVC with GPU acceleration and AAC audio, plus scale it down to 480p, you would normally have to run a command like: ```sh -ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i test.mp4 -vf scale=-1:480 -c:v hevc_nvenc -preset fast -c:a aac -c:s copy -map 0 out.mp4 +ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i test.mp4 -vf scale=-1:480 -c:v hevc_nvenc -preset fast -c:a aac -c:s copy -map 0:v -map 0:a -map 0:s out.mp4 ``` Using this toolkit, it would be this instead: ```sh @@ -118,7 +118,14 @@ The source file is left intact. - `manage-media convert --vc copy --ac copy --start 3m45s --end 10m00s ` ### Hardware Acceleration -If your `ffmpeg` [supports it](https://trac.ffmpeg.org/wiki/HWAccelIntro#CUDANVENCNVDEC), you can use NVIDIA GPU hardware acceleration to speed up the conversion. You can see the supported codecs for decoding & encoding for each GPU [here](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new). + +Your `ffmpeg` must support the hardware acceleration you want to use. You can check this with `ffmpeg -hwaccels`. If you see `cuda` or `videotoolbox`, then you can use the hardware acceleration below. + +Using this can speed up the conversion process significantly! + +#### NVIDIA (`cuda`) + +If your `ffmpeg` [supports it](https://trac.ffmpeg.org/wiki/HWAccelIntro#CUDANVENCNVDEC) and you have an NVIDIA GPU, you can use hardware acceleration to speed up the conversion. You can see the supported codecs for decoding & encoding for each GPU [here](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new). To use this, just add `--hardware-nvidia` or `--hw-nv` to the `manage-media convert` command. @@ -126,6 +133,16 @@ To use this, just add `--hardware-nvidia` or `--hw-nv` to the `manage-media conv manage-media convert --hw-nv --video-codec hevc --audio-codec ac3 ``` +#### Apple (`videotoolbox`) + +If your `ffmpeg` [supports it](https://trac.ffmpeg.org/wiki/HWAccelIntro#VideoToolbox) and you are using a Mac with Apple Silicon, you can use hardware acceleration for encoding by adding `--hardware-apple` or `--hw-apple` to the `manage-media convert` command. + +``` +manage-media convert --hw-apple --video-codec h264 --audio-codec copy +``` + +Note: this might also work onn Intel Macs, but it is untested. + ## metadata Get a simple output of metadata for a file. Or get lots of metadata in json format diff --git a/media_management_scripts/commands/common.py b/media_management_scripts/commands/common.py index 52204ff..c9727a6 100644 --- a/media_management_scripts/commands/common.py +++ b/media_management_scripts/commands/common.py @@ -165,6 +165,16 @@ def __call__(self, parser, namespace, values, option_string=None): help="Use NVIDIA hardware acceleration for decoding and encoding", ) +convert_parent_parser.add_argument( + "--hardware-apple", + "--hw-apple", + dest="hardware_apple", + default=False, + action="store_const", + const=True, + help="Use Apple Silicon hardware acceleration for encoding", +) + __all__ = [ # Parsers "parent_parser", diff --git a/media_management_scripts/convert.py b/media_management_scripts/convert.py index 637c5e2..f4a23f9 100644 --- a/media_management_scripts/convert.py +++ b/media_management_scripts/convert.py @@ -47,7 +47,7 @@ def execute(args, print_output=True): return ret -def auto_bitrate_from_config(resolution, convert_config): +def auto_bitrate_from_config(resolution, convert_config: ConvertConfig): if convert_config.scale: resolution = resolution_name(convert_config.scale) if resolution == Resolution.LOW_DEF: @@ -137,6 +137,13 @@ def convert_with_config( f"Video codec {config.video_codec} not supported by nvidia hardware acceleration" ) args.extend(["-c:v", vc]) + elif config.hardware_apple: + vc = VideoCodec.from_code_name(config.video_codec).apple_codec_name + if not vc: + raise Exception( + f"Video codec {config.video_codec} not supported by nvidia hardware acceleration" + ) + args.extend(["-c:v", vc]) else: args.extend(["-c:v", config.video_codec]) crf = config.crf @@ -145,7 +152,7 @@ def convert_with_config( VideoCodec.H264.equals(config.video_codec) and config.bitrate is not None and config.bitrate != "disabled" - and not config.hardware_nvidia + and not config.hardware_accelerated ): crf = 1 # -x264-params vbv-maxrate=1666:vbv-bufsize=3332:crf-max=22:qpmax=34 @@ -157,6 +164,13 @@ def convert_with_config( str(bitrate), str(bitrate * 2) ) args.extend(["-x264-params", params]) + elif ( + VideoCodec.H264.equals(config.video_codec) + and config.bitrate == "auto" + and config.hardware_apple + ): + # TODO this is probably not the best way to do this + args.extend(["-constant_bit_rate", "true"]) elif ( VideoCodec.H265.equals(config.video_codec) and config.bitrate is not None diff --git a/media_management_scripts/support/encoding.py b/media_management_scripts/support/encoding.py index 151bea2..c16719c 100644 --- a/media_management_scripts/support/encoding.py +++ b/media_management_scripts/support/encoding.py @@ -69,10 +69,10 @@ def resolution_name(height): class VideoCodec(Enum): - H264 = ("libx264", ["h264"], "h264_nvenc") - H265 = ("libx265", ["hevc", "h265"], "hevc_nvenc") - MPEG2 = ("mpeg2video", ["mpeg2video", "mpeg2"], None) - COPY = ("copy", ["copy"], "copy") + H264 = ("libx264", ["h264"], "h264_nvenc", "h264_videotoolbox") + H265 = ("libx265", ["hevc", "h265"], "hevc_nvenc", "hevc_videotoolbox") + MPEG2 = ("mpeg2video", ["mpeg2video", "mpeg2"], None, None) + COPY = ("copy", ["copy"], "copy", "copy") @property def ffmpeg_encoder_name(self): @@ -90,6 +90,10 @@ def codec_names(self): def nvidia_codec_name(self): return self.value[2] + @property + def apple_codec_name(self): + return self.value[3] + @staticmethod def from_code_name(name): for vc in VideoCodec: diff --git a/media_management_scripts/utils.py b/media_management_scripts/utils.py index 491e18b..238d149 100644 --- a/media_management_scripts/utils.py +++ b/media_management_scripts/utils.py @@ -107,6 +107,11 @@ class ConvertConfig(NamedTuple): video_codec: str = VideoCodec.H264.ffmpeg_encoder_name audio_codec: str = AudioCodec.AAC.ffmpeg_codec_name hardware_nvidia: bool = False + hardware_apple: bool = False + + @property + def hardware_accelerated(self): + return self.hardware_nvidia or self.hardware_apple def convert_config_from_config_section(