Find available hardware encoders using Mac's VideoToolbox framework

September 08, 2023

The latest Arm Mac devices have built-in hardware encoders for common video codecs such as HEVC (H.265) and H.264, the popular x265 and x264 libraries provide a software implementation but this can be slow. As an example, the tech specs for an M1 MacBook Pro says it can:

Media engine

  • Hardware-accelerated H.264, HEVC, ProRes, and ProRes RAW
  • Video decode engine
  • Video encode engine
  • ProRes encode and decode engine

Apple provide the videtoolbox framework for this. It can be called from Obj-C/C code as well as Swift code. There is a function called VTCopyVideoEncoderList that returns a pointer to an array of dictionaries that lists the available encoders for you to use, and whether they’re hardware accelerated.

Using clang you can compile and link with

clang -framework VideoToolbox -framework CoreMedia -framework Foundation enc.c
#include <CoreFoundation/CoreFoundation.h>
#include <CoreMedia/CoreMedia.h>
#include <CoreVideo/CoreVideo.h>
#include <VideoToolbox/VideoToolbox.h>
#include <stdbool.h>
#include <stdio.h>

void printAvailableVideoEncoders();

int main(void) {
  bool vp9hardware = VTIsHardwareDecodeSupported(kCMVideoCodecType_VP9);
  printf("Is VP9 hardware decode: %d\n", vp9hardware);
  printAvailableVideoEncoders();
  return 0;
}

void printAvailableVideoEncoders() {
  CFArrayRef encoderList = NULL;
  CFDictionaryRef encoderDict = NULL;
  CFStringRef encoderName = NULL;
  CFBooleanRef isHardware = NULL;

  OSStatus status = VTCopyVideoEncoderList(NULL, &encoderList);
  if (status != 0) {
    printf("Failed to fetch encoder list\n");
    return;
  }

  CFIndex encoderCount = CFArrayGetCount(encoderList);
  for (CFIndex i = 0; i < encoderCount; i++) {
    encoderDict = CFArrayGetValueAtIndex(encoderList, i);
    if (encoderDict) {
      encoderName =
          CFDictionaryGetValue(encoderDict, kVTVideoEncoderList_EncoderName);
      isHardware = CFDictionaryGetValue(
          encoderDict, kVTVideoEncoderList_IsHardwareAccelerated);

      if (encoderName) {
        printf("Encoder: %s\n",
               CFStringGetCStringPtr(encoderName, kCFStringEncodingUTF8));
      }

      if (isHardware) {
        if (CFBooleanGetValue(isHardware)) {
          printf("Hardware Accelerated: Yes\n");
        } else {
          printf("Hardware Accelerated: No\n");
        }
      } else {
        printf("Hardware Accelerated: No\n");
      }
    }
  }
  if (encoderList) {
    CFRelease(encoderList);
  }
}

The output on an M1 MacBook Pro looks like (Apple have recently added a VP9 constant to VideoToolbox, so hopefully M3 devices support native VP9 playback)

Is VP9 hardware decode: 0
Encoder: Apple 24-bit RGB
Hardware Accelerated: No
Encoder: Apple 32-bit ARGB
Hardware Accelerated: No
Encoder: Apple ProRes 422
Hardware Accelerated: No
Encoder: Apple ProRes 422 HQ
Hardware Accelerated: No
Encoder: Apple ProRes 422 LT
Hardware Accelerated: No
Encoder: Apple ProRes 422 Proxy
Hardware Accelerated: No
Encoder: Apple ProRes 4444
Hardware Accelerated: No
Encoder: Apple ProRes 4444 XQ
Hardware Accelerated: No
Encoder: Apple Depth (HEVC)-Apple HEVC (HW)
Hardware Accelerated: Yes
Encoder: Apple Depth (HEVC)-Apple HEVC (SW)
Hardware Accelerated: No
Encoder: Apple Disparity (HEVC)-Apple HEVC (HW)
Hardware Accelerated: Yes
Encoder: Apple Disparity (HEVC)-Apple HEVC (SW)
Hardware Accelerated: No
Encoder: Apple H.263 (SW)
Hardware Accelerated: No
Encoder: Apple H.264 (HW)
Hardware Accelerated: Yes
Encoder: Apple H.264 (SW)
Hardware Accelerated: No
Encoder: Apple HEVC (HW)
Hardware Accelerated: Yes
Encoder: Apple HEVC (SW)
Hardware Accelerated: No
Encoder: Apple JPEG
Hardware Accelerated: No
Encoder: JPEG (HW)
Hardware Accelerated: Yes
Encoder: Apple Muxed Alpha-Apple HEVC (HW)
Hardware Accelerated: Yes
Encoder: Apple Muxed Alpha-Apple HEVC (SW)
Hardware Accelerated: No
Back to top