aboutsummaryrefslogtreecommitdiffstats
path: root/libavcodec/videotoolbox_vp9.c
diff options
context:
space:
mode:
authorrcombs <rcombs@rcombs.me>2021-11-13 02:43:06 -0600
committerrcombs <rcombs@rcombs.me>2021-11-28 16:40:58 -0600
commita41a2efc85f8c88caec10040ee437562f9d0b947 (patch)
tree133c31e9eb66bc1a180f9da2d545b5beebcd1ad8 /libavcodec/videotoolbox_vp9.c
parente3c6cc96cf2f0b2c22dee80a53a01a5fe4fea009 (diff)
downloadffmpeg-a41a2efc85f8c88caec10040ee437562f9d0b947.tar.gz
lavc/videotoolbox: add VP9 hardware acceleration
On M1 Max, this supports profiles 0 and 2, but not 1 and 3.
Diffstat (limited to 'libavcodec/videotoolbox_vp9.c')
-rw-r--r--libavcodec/videotoolbox_vp9.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/libavcodec/videotoolbox_vp9.c b/libavcodec/videotoolbox_vp9.c
new file mode 100644
index 0000000000..1b6d08f00b
--- /dev/null
+++ b/libavcodec/videotoolbox_vp9.c
@@ -0,0 +1,140 @@
+/*
+ * Videotoolbox hardware acceleration for VP9
+ *
+ * copyright (c) 2021 rcombs
+ *
+ * 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 "config.h"
+#include "videotoolbox.h"
+#include "libavutil/hwcontext_videotoolbox.h"
+#include "vt_internal.h"
+#include "libavutil/avutil.h"
+#include "libavutil/frame.h"
+#include "libavutil/hwcontext.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/pixdesc.h"
+#include "decode.h"
+#include "internal.h"
+#include "vp9shared.h"
+
+enum VPX_CHROMA_SUBSAMPLING
+{
+ VPX_SUBSAMPLING_420_VERTICAL = 0,
+ VPX_SUBSAMPLING_420_COLLOCATED_WITH_LUMA = 1,
+ VPX_SUBSAMPLING_422 = 2,
+ VPX_SUBSAMPLING_444 = 3,
+};
+
+static int get_vpx_chroma_subsampling(enum AVPixelFormat pixel_format,
+ enum AVChromaLocation chroma_location)
+{
+ int chroma_w, chroma_h;
+ if (av_pix_fmt_get_chroma_sub_sample(pixel_format, &chroma_w, &chroma_h) == 0) {
+ if (chroma_w == 1 && chroma_h == 1) {
+ return (chroma_location == AVCHROMA_LOC_LEFT)
+ ? VPX_SUBSAMPLING_420_VERTICAL
+ : VPX_SUBSAMPLING_420_COLLOCATED_WITH_LUMA;
+ } else if (chroma_w == 1 && chroma_h == 0) {
+ return VPX_SUBSAMPLING_422;
+ } else if (chroma_w == 0 && chroma_h == 0) {
+ return VPX_SUBSAMPLING_444;
+ }
+ }
+ return -1;
+}
+
+CFDataRef ff_videotoolbox_vpcc_extradata_create(AVCodecContext *avctx)
+{
+ const VP9SharedContext *h = avctx->priv_data;
+ CFDataRef data = NULL;
+ uint8_t *p;
+ int vt_extradata_size;
+ uint8_t *vt_extradata;
+ int subsampling = get_vpx_chroma_subsampling(avctx->sw_pix_fmt, avctx->chroma_sample_location);
+
+ vt_extradata_size = 1 + 3 + 6 + 2;
+ vt_extradata = av_malloc(vt_extradata_size);
+
+ if (subsampling < 0)
+ return NULL;
+
+ if (!vt_extradata)
+ return NULL;
+
+ p = vt_extradata;
+
+ *p++ = 1; /* version */
+ AV_WB24(p + 1, 0); /* flags */
+ p += 3;
+
+ *p++ = h->h.profile;
+ *p++ = avctx->level;
+ *p++ = (h->h.bpp << 4) | (subsampling << 1) | (avctx->color_range == AVCOL_RANGE_JPEG);
+ *p++ = avctx->color_primaries;
+ *p++ = avctx->color_trc;
+ *p++ = avctx->colorspace;
+
+ AV_WB16(p + 0, 0);
+ p += 2;
+
+ av_assert0(p - vt_extradata == vt_extradata_size);
+
+ data = CFDataCreate(kCFAllocatorDefault, vt_extradata, vt_extradata_size);
+ av_free(vt_extradata);
+ return data;
+}
+
+static int videotoolbox_vp9_start_frame(AVCodecContext *avctx,
+ const uint8_t *buffer,
+ uint32_t size)
+{
+ return 0;
+}
+
+static int videotoolbox_vp9_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_vp9_end_frame(AVCodecContext *avctx)
+{
+ const VP9SharedContext *h = avctx->priv_data;
+ AVFrame *frame = h->frames[CUR_FRAME].tf.f;
+
+ return ff_videotoolbox_common_end_frame(avctx, frame);
+}
+
+const AVHWAccel ff_vp9_videotoolbox_hwaccel = {
+ .name = "vp9_videotoolbox",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_VP9,
+ .pix_fmt = AV_PIX_FMT_VIDEOTOOLBOX,
+ .alloc_frame = ff_videotoolbox_alloc_frame,
+ .start_frame = videotoolbox_vp9_start_frame,
+ .decode_slice = videotoolbox_vp9_decode_slice,
+ .end_frame = videotoolbox_vp9_end_frame,
+ .frame_params = ff_videotoolbox_frame_params,
+ .init = ff_videotoolbox_common_init,
+ .uninit = ff_videotoolbox_uninit,
+ .priv_data_size = sizeof(VTContext),
+};