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(