|
|
|
/*
|
|
|
|
* 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/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),
|
|
|
|
};
|