Skip to content

Commit

Permalink
Add support for apple hardware acceleration (#16)
Browse files Browse the repository at this point in the history
Adds support for using Video Toolbox encoding on MacOS if the `ffmpeg`
supports it.

Add `--hardware-apple` or `--hw-apple` to `manage-media convert` to
enable this.
  • Loading branch information
raydouglass authored May 18, 2024
1 parent f22fb9d commit 8714fec
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 8 deletions.
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -118,14 +118,31 @@ The source file is left intact.
- `manage-media convert --vc copy --ac copy --start 3m45s --end 10m00s <input> <output>`

### 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.

```
manage-media convert --hw-nv --video-codec hevc --audio-codec ac3 <input> <output>
```

#### 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 <input> <output>
```

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
Expand Down
10 changes: 10 additions & 0 deletions media_management_scripts/commands/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
18 changes: 16 additions & 2 deletions media_management_scripts/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
12 changes: 8 additions & 4 deletions media_management_scripts/support/encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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:
Expand Down
5 changes: 5 additions & 0 deletions media_management_scripts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down

0 comments on commit 8714fec

Please sign in to comment.