diff mbox series

[FFmpeg-devel,15/16] lavc/proresdec: add videotoolbox hwaccel

Message ID 20211122215821.9849-15-rcombs@rcombs.me
State New
Headers show
Series [FFmpeg-devel,01/16] ffmpeg: remove ffmpeg_videotoolbox
Related show

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished
andriy/make_ppc success Make finished
andriy/make_fate_ppc success Make fate finished

Commit Message

rcombs Nov. 22, 2021, 9:58 p.m. UTC
---
 Changelog                 |  1 +
 configure                 |  2 ++
 libavcodec/hwaccels.h     |  1 +
 libavcodec/proresdec2.c   | 12 ++++++-
 libavcodec/videotoolbox.c | 74 ++++++++++++++++++++++++++++++++++++++-
 5 files changed, 88 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/Changelog b/Changelog
index d6be6bbe4f..e80b3fd82d 100644
--- a/Changelog
+++ b/Changelog
@@ -32,6 +32,7 @@  version <next>:
 - huesaturation video filter
 - colorspectrum source video filter
 - VideoToolbox VP9 hwaccel
+- VideoToolbox ProRes hwaccel
 
 
 version 4.4:
diff --git a/configure b/configure
index 262261b544..599ced3df6 100755
--- a/configure
+++ b/configure
@@ -3056,6 +3056,8 @@  mpeg4_vdpau_hwaccel_deps="vdpau"
 mpeg4_vdpau_hwaccel_select="mpeg4_decoder"
 mpeg4_videotoolbox_hwaccel_deps="videotoolbox"
 mpeg4_videotoolbox_hwaccel_select="mpeg4_decoder"
+prores_videotoolbox_hwaccel_deps="videotoolbox"
+prores_videotoolbox_hwaccel_select="prores_decoder"
 vc1_d3d11va_hwaccel_deps="d3d11va"
 vc1_d3d11va_hwaccel_select="vc1_decoder"
 vc1_d3d11va2_hwaccel_deps="d3d11va"
diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h
index 65e778f3e4..1e7b464950 100644
--- a/libavcodec/hwaccels.h
+++ b/libavcodec/hwaccels.h
@@ -60,6 +60,7 @@  extern const AVHWAccel ff_mpeg4_nvdec_hwaccel;
 extern const AVHWAccel ff_mpeg4_vaapi_hwaccel;
 extern const AVHWAccel ff_mpeg4_vdpau_hwaccel;
 extern const AVHWAccel ff_mpeg4_videotoolbox_hwaccel;
+extern const AVHWAccel ff_prores_videotoolbox_hwaccel;
 extern const AVHWAccel ff_vc1_d3d11va_hwaccel;
 extern const AVHWAccel ff_vc1_d3d11va2_hwaccel;
 extern const AVHWAccel ff_vc1_dxva2_hwaccel;
diff --git a/libavcodec/proresdec2.c b/libavcodec/proresdec2.c
index 5b1d7da693..719194f21e 100644
--- a/libavcodec/proresdec2.c
+++ b/libavcodec/proresdec2.c
@@ -33,6 +33,7 @@ 
 
 #include "avcodec.h"
 #include "get_bits.h"
+#include "hwconfig.h"
 #include "idctdsp.h"
 #include "internal.h"
 #include "profiles.h"
@@ -268,12 +269,15 @@  static int decode_frame_header(ProresContext *ctx, const uint8_t *buf,
     }
 
     if (pix_fmt != ctx->pix_fmt) {
-#define HWACCEL_MAX 0
+#define HWACCEL_MAX (CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL)
         enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts;
         int ret;
 
         ctx->pix_fmt = pix_fmt;
 
+#if CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL
+        *fmtp++ = AV_PIX_FMT_VIDEOTOOLBOX;
+#endif
         *fmtp++ = ctx->pix_fmt;
         *fmtp = AV_PIX_FMT_NONE;
 
@@ -864,4 +868,10 @@  const AVCodec ff_prores_decoder = {
     .capabilities   = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS,
     .profiles       = NULL_IF_CONFIG_SMALL(ff_prores_profiles),
     .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
+    .hw_configs     = (const AVCodecHWConfigInternal *const []) {
+#if CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL
+        HWACCEL_VIDEOTOOLBOX(prores),
+#endif
+        NULL
+    },
 };
diff --git a/libavcodec/videotoolbox.c b/libavcodec/videotoolbox.c
index 542fe9316a..40d231acc1 100644
--- a/libavcodec/videotoolbox.c
+++ b/libavcodec/videotoolbox.c
@@ -32,6 +32,7 @@ 
 #include "h264dec.h"
 #include "hevcdec.h"
 #include "mpegvideo.h"
+#include "proresdec.h"
 #include <Availability.h>
 #include <AvailabilityMacros.h>
 #include <TargetConditionals.h>
@@ -186,7 +187,6 @@  CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx)
     int pps_size = escape_ps(NULL, h->ps.pps->data, h->ps.pps->data_size);
     int vt_extradata_size;
     uint8_t *vt_extradata;
-    int i;
 
     vt_extradata_size = 6 + 2 + sps_size + 3 + pps_size;
     vt_extradata = av_malloc(vt_extradata_size);
@@ -873,6 +873,31 @@  static int videotoolbox_start(AVCodecContext *avctx)
     case AV_CODEC_ID_MPEG4 :
         videotoolbox->cm_codec_type = kCMVideoCodecType_MPEG4Video;
         break;
+    case AV_CODEC_ID_PRORES :
+        switch (avctx->codec_tag) {
+        case MKTAG('a','p','c','o'):
+            videotoolbox->cm_codec_type = kCMVideoCodecType_AppleProRes422Proxy;
+            break;
+        case MKTAG('a','p','c','s'):
+            videotoolbox->cm_codec_type = kCMVideoCodecType_AppleProRes422LT;
+            break;
+        case MKTAG('a','p','c','n'):
+            videotoolbox->cm_codec_type = kCMVideoCodecType_AppleProRes422;
+            break;
+        case MKTAG('a','p','c','h'):
+            videotoolbox->cm_codec_type = kCMVideoCodecType_AppleProRes422HQ;
+            break;
+        case MKTAG('a','p','4','h'):
+            videotoolbox->cm_codec_type = kCMVideoCodecType_AppleProRes4444;
+            break;
+        case MKTAG('a','p','4','x'):
+            videotoolbox->cm_codec_type = kCMVideoCodecType_AppleProRes4444XQ;
+            break;
+        default:
+            videotoolbox->cm_codec_type = avctx->codec_tag;
+            av_log(avctx, AV_LOG_WARNING, "Unknown prores profile %d\n", avctx->codec_tag);
+        }
+        break;
     case AV_CODEC_ID_VP9 :
         videotoolbox->cm_codec_type = kCMVideoCodecType_VP9;
         break;
@@ -880,6 +905,14 @@  static int videotoolbox_start(AVCodecContext *avctx)
         break;
     }
 
+#if defined(MAC_OS_X_VERSION_10_9) && !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9)
+    if (avctx->codec_id == AV_CODEC_ID_PRORES) {
+        if (__builtin_available(macOS 10.9, *)) {
+            VTRegisterProfessionalVideoWorkflowVideoDecoders();
+        }
+    }
+#endif
+
 #if defined(MAC_OS_VERSION_11_0) && !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0)
     if (__builtin_available(macOS 11.0, *)) {
         VTRegisterSupplementalVideoDecoderIfAvailable(videotoolbox->cm_codec_type);
@@ -1068,6 +1101,30 @@  static int videotoolbox_mpeg_end_frame(AVCodecContext *avctx)
     return ff_videotoolbox_common_end_frame(avctx, frame);
 }
 
+static int videotoolbox_prores_start_frame(AVCodecContext *avctx,
+                                         const uint8_t *buffer,
+                                         uint32_t size)
+{
+    return 0;
+}
+
+static int videotoolbox_prores_decode_slice(AVCodecContext *avctx,
+                                          const uint8_t *buffer,
+                                          uint32_t size)
+{
+    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
+
+    return ff_videotoolbox_buffer_copy(vtctx, buffer, size);
+}
+
+static int videotoolbox_prores_end_frame(AVCodecContext *avctx)
+{
+    ProresContext *ctx = avctx->priv_data;
+    AVFrame *frame = ctx->frame;
+
+    return ff_videotoolbox_common_end_frame(avctx, frame);
+}
+
 static enum AVPixelFormat videotoolbox_best_pixel_format(AVCodecContext *avctx) {
     const AVPixFmtDescriptor *descriptor = av_pix_fmt_desc_get(avctx->sw_pix_fmt);
     if (!descriptor)
@@ -1291,6 +1348,21 @@  const AVHWAccel ff_mpeg4_videotoolbox_hwaccel = {
     .priv_data_size = sizeof(VTContext),
 };
 
+const AVHWAccel ff_prores_videotoolbox_hwaccel = {
+    .name           = "prores_videotoolbox",
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_PRORES,
+    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
+    .alloc_frame    = ff_videotoolbox_alloc_frame,
+    .start_frame    = videotoolbox_prores_start_frame,
+    .decode_slice   = videotoolbox_prores_decode_slice,
+    .end_frame      = videotoolbox_prores_end_frame,
+    .frame_params   = ff_videotoolbox_frame_params,
+    .init           = ff_videotoolbox_common_init,
+    .uninit         = ff_videotoolbox_uninit,
+    .priv_data_size = sizeof(VTContext),
+};
+
 static AVVideotoolboxContext *av_videotoolbox_alloc_context_with_pix_fmt(enum AVPixelFormat pix_fmt,
                                                                          bool full_range)
 {