/* * 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 "libavutil/mem.h" #include "vt_internal.h" #include "libavutil/avassert.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 "hwaccel_internal.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 FFHWAccel ff_vp9_videotoolbox_hwaccel = { .p.name = "vp9_videotoolbox", .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_VP9, .p.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), };