Skip to content

Commit

Permalink
WIP avcodec/videotoolbox: add AV1 hardware acceleration
Browse files Browse the repository at this point in the history
  • Loading branch information
jeeb committed Nov 10, 2023
1 parent 590de39 commit 2a179d5
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 0 deletions.
4 changes: 4 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -2388,6 +2388,7 @@ TYPES_LIST="
kCMVideoCodecType_HEVC
kCMVideoCodecType_HEVCWithAlpha
kCMVideoCodecType_VP9
kCMVideoCodecType_AV1
kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange
kCVPixelFormatType_422YpCbCr8BiPlanarVideoRange
kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange
Expand Down Expand Up @@ -3063,6 +3064,8 @@ av1_vaapi_hwaccel_deps="vaapi VADecPictureParameterBufferAV1_bit_depth_idx"
av1_vaapi_hwaccel_select="av1_decoder"
av1_vdpau_hwaccel_deps="vdpau VdpPictureInfoAV1"
av1_vdpau_hwaccel_select="av1_decoder"
av1_videotoolbox_hwaccel_deps="videotoolbox"
av1_videotoolbox_hwaccel_select="av1_decoder"
av1_vulkan_hwaccel_deps="vulkan"
av1_vulkan_hwaccel_select="av1_decoder"
h263_vaapi_hwaccel_deps="vaapi"
Expand Down Expand Up @@ -6536,6 +6539,7 @@ enabled videotoolbox && {
check_func_headers CoreMedia/CMFormatDescription.h kCMVideoCodecType_HEVC "-framework CoreMedia"
check_func_headers CoreMedia/CMFormatDescription.h kCMVideoCodecType_HEVCWithAlpha "-framework CoreMedia"
check_func_headers CoreMedia/CMFormatDescription.h kCMVideoCodecType_VP9 "-framework CoreMedia"
check_func_headers CoreMedia/CMFormatDescription.h kCMVideoCodecType_AV1 "-framework CoreMedia"
check_func_headers CoreVideo/CVPixelBuffer.h kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange "-framework CoreVideo"
check_func_headers CoreVideo/CVPixelBuffer.h kCVPixelFormatType_422YpCbCr8BiPlanarVideoRange "-framework CoreVideo"
check_func_headers CoreVideo/CVPixelBuffer.h kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange "-framework CoreVideo"
Expand Down
1 change: 1 addition & 0 deletions libavcodec/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,7 @@ OBJS-$(CONFIG_AV1_DXVA2_HWACCEL) += dxva2_av1.o
OBJS-$(CONFIG_AV1_NVDEC_HWACCEL) += nvdec_av1.o
OBJS-$(CONFIG_AV1_VAAPI_HWACCEL) += vaapi_av1.o
OBJS-$(CONFIG_AV1_VDPAU_HWACCEL) += vdpau_av1.o
OBJS-$(CONFIG_AV1_VIDEOTOOLBOX_HWACCEL) += videotoolbox_av1.o
OBJS-$(CONFIG_AV1_VULKAN_HWACCEL) += vulkan_av1.o
OBJS-$(CONFIG_H263_VAAPI_HWACCEL) += vaapi_mpeg4.o
OBJS-$(CONFIG_H263_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o
Expand Down
10 changes: 10 additions & 0 deletions libavcodec/av1dec.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ static int get_pixel_format(AVCodecContext *avctx)
CONFIG_AV1_NVDEC_HWACCEL + \
CONFIG_AV1_VAAPI_HWACCEL + \
CONFIG_AV1_VDPAU_HWACCEL + \
CONFIG_AV1_VIDEOTOOLBOX_HWACCEL + \
CONFIG_AV1_VULKAN_HWACCEL)
enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts;

Expand All @@ -538,6 +539,9 @@ static int get_pixel_format(AVCodecContext *avctx)
#if CONFIG_AV1_VDPAU_HWACCEL
*fmtp++ = AV_PIX_FMT_VDPAU;
#endif
#if CONFIG_AV1_VIDEOTOOLBOX_HWACCEL
*fmtp++ = AV_PIX_FMT_VIDEOTOOLBOX;
#endif
#if CONFIG_AV1_VULKAN_HWACCEL
*fmtp++ = AV_PIX_FMT_VULKAN;
#endif
Expand All @@ -559,6 +563,9 @@ static int get_pixel_format(AVCodecContext *avctx)
#if CONFIG_AV1_VDPAU_HWACCEL
*fmtp++ = AV_PIX_FMT_VDPAU;
#endif
#if CONFIG_AV1_VIDEOTOOLBOX_HWACCEL
*fmtp++ = AV_PIX_FMT_VIDEOTOOLBOX;
#endif
#if CONFIG_AV1_VULKAN_HWACCEL
*fmtp++ = AV_PIX_FMT_VULKAN;
#endif
Expand Down Expand Up @@ -1516,6 +1523,9 @@ const FFCodec ff_av1_decoder = {
#if CONFIG_AV1_VDPAU_HWACCEL
HWACCEL_VDPAU(av1),
#endif
#if CONFIG_AV1_VIDEOTOOLBOX_HWACCEL
HWACCEL_VIDEOTOOLBOX(av1),
#endif
#if CONFIG_AV1_VULKAN_HWACCEL
HWACCEL_VULKAN(av1),
#endif
Expand Down
1 change: 1 addition & 0 deletions libavcodec/hwaccels.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ extern const struct FFHWAccel ff_av1_dxva2_hwaccel;
extern const struct FFHWAccel ff_av1_nvdec_hwaccel;
extern const struct FFHWAccel ff_av1_vaapi_hwaccel;
extern const struct FFHWAccel ff_av1_vdpau_hwaccel;
extern const struct FFHWAccel ff_av1_videotoolbox_hwaccel;
extern const struct FFHWAccel ff_av1_vulkan_hwaccel;
extern const struct FFHWAccel ff_h263_vaapi_hwaccel;
extern const struct FFHWAccel ff_h263_videotoolbox_hwaccel;
Expand Down
14 changes: 14 additions & 0 deletions libavcodec/videotoolbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ enum { kCMVideoCodecType_HEVC = 'hvc1' };
enum { kCMVideoCodecType_VP9 = 'vp09' };
#endif

#if !HAVE_KCMVIDEOCODECTYPE_AV1
enum { kCMVideoCodecType_AV1 = 'av01' };
#endif

#define VIDEOTOOLBOX_ESDS_EXTRADATA_PADDING 12

typedef struct VTHWFrame {
Expand Down Expand Up @@ -842,6 +846,13 @@ static CFDictionaryRef videotoolbox_decoder_config_create(CMVideoCodecType codec
if (data)
CFDictionarySetValue(avc_info, CFSTR("vpcC"), data);
break;
#endif
#if CONFIG_AV1_VIDEOTOOLBOX_HWACCEL
case kCMVideoCodecType_AV1 :
data = ff_videotoolbox_av1c_extradata_create(avctx);
if (data)
CFDictionarySetValue(avc_info, CFSTR("av1C"), data);
break;
#endif
default:
break;
Expand Down Expand Up @@ -908,6 +919,9 @@ static int videotoolbox_start(AVCodecContext *avctx)
case AV_CODEC_ID_VP9 :
videotoolbox->cm_codec_type = kCMVideoCodecType_VP9;
break;
case AV_CODEC_ID_AV1 :
videotoolbox->cm_codec_type = kCMVideoCodecType_AV1;
break;
default :
break;
}
Expand Down
99 changes: 99 additions & 0 deletions libavcodec/videotoolbox_av1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Videotoolbox hardware acceleration for AV1
* Copyright (c) 2023 Jan Ekström
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "libavformat/avio.h"
#include "libavformat/avio_internal.h"
#define CALLED_FROM_AVCODEC 1
#include "libavformat/av1.c"
#undef CALLED_FROM_AVCODEC

#include "libavutil/avutil.h"
#include "libavutil/frame.h"
#include "libavutil/pixfmt.h"

#include "av1dec.h"
#include "codec_id.h"
#include "hwaccel_internal.h"
#include "internal.h"
#include "vt_internal.h"

CFDataRef ff_videotoolbox_av1c_extradata_create(AVCodecContext *avctx)
{
AVIOContext *pb;
uint8_t *buf;
CFDataRef data = NULL;
int buf_size = 0;
int ret = avio_open_dyn_buf(&pb);
if (ret < 0)
return NULL;

ret = ff_isom_write_av1c(pb, avctx->extradata, avctx->extradata_size, 1);
if (ret < 0)
goto fail;

buf_size = avio_get_dyn_buf(pb, &buf);
if (buf_size)
data = CFDataCreate(kCFAllocatorDefault, buf, buf_size);

fail:
ffio_free_dyn_buf(&pb);

return data;
}

static int videotoolbox_av1_start_frame(AVCodecContext *avctx,
const uint8_t *buffer,
uint32_t size)
{
return 0;
}

static int videotoolbox_av1_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_av1_end_frame(AVCodecContext *avctx)
{
const AV1DecContext *s = avctx->priv_data;
AVFrame *frame = s->cur_frame.f;

return ff_videotoolbox_common_end_frame(avctx, frame);
}

const FFHWAccel ff_av1_videotoolbox_hwaccel = {
.p.name = "av1_videotoolbox",
.p.type = AVMEDIA_TYPE_VIDEO,
.p.id = AV_CODEC_ID_AV1,
.p.pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX,
.alloc_frame = ff_videotoolbox_alloc_frame,
.start_frame = videotoolbox_av1_start_frame,
.decode_slice = videotoolbox_av1_decode_slice,
.end_frame = videotoolbox_av1_end_frame,
.frame_params = ff_videotoolbox_frame_params,
.init = ff_videotoolbox_common_init,
.uninit = ff_videotoolbox_uninit,
.priv_data_size = sizeof(VTContext),
};
1 change: 1 addition & 0 deletions libavcodec/vt_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ int ff_videotoolbox_h264_decode_slice(AVCodecContext *avctx,
const uint8_t *buffer,
uint32_t size);
int ff_videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame);
CFDataRef ff_videotoolbox_av1c_extradata_create(AVCodecContext *avctx);
CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx);
CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx);
CFDataRef ff_videotoolbox_vpcc_extradata_create(AVCodecContext *avctx);
Expand Down

2 comments on commit 2a179d5

@Foul-Tarnished
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this ever get pushed to ffmpeg ? 🙏

@Foul-Tarnished
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jeeb I can test on my m3 if you need someone with the HW

Please sign in to comment.