1 /*
2  * Videotoolbox hardware acceleration for VP9
3  *
4  * copyright (c) 2021 rcombs
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include "config.h"
24 #include "videotoolbox.h"
25 #include "libavutil/hwcontext_videotoolbox.h"
26 #include "vt_internal.h"
27 #include "libavutil/avutil.h"
28 #include "libavutil/frame.h"
29 #include "libavutil/hwcontext.h"
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/pixdesc.h"
32 #include "decode.h"
33 #include "internal.h"
34 #include "vp9shared.h"
35 
36 enum VPX_CHROMA_SUBSAMPLING
37 {
38     VPX_SUBSAMPLING_420_VERTICAL = 0,
39     VPX_SUBSAMPLING_420_COLLOCATED_WITH_LUMA = 1,
40     VPX_SUBSAMPLING_422 = 2,
41     VPX_SUBSAMPLING_444 = 3,
42 };
43 
get_vpx_chroma_subsampling(enum AVPixelFormat pixel_format, enum AVChromaLocation chroma_location)44 static int get_vpx_chroma_subsampling(enum AVPixelFormat pixel_format,
45                                       enum AVChromaLocation chroma_location)
46 {
47     int chroma_w, chroma_h;
48     if (av_pix_fmt_get_chroma_sub_sample(pixel_format, &chroma_w, &chroma_h) == 0) {
49         if (chroma_w == 1 && chroma_h == 1) {
50             return (chroma_location == AVCHROMA_LOC_LEFT)
51                        ? VPX_SUBSAMPLING_420_VERTICAL
52                        : VPX_SUBSAMPLING_420_COLLOCATED_WITH_LUMA;
53         } else if (chroma_w == 1 && chroma_h == 0) {
54             return VPX_SUBSAMPLING_422;
55         } else if (chroma_w == 0 && chroma_h == 0) {
56             return VPX_SUBSAMPLING_444;
57         }
58     }
59     return -1;
60 }
61 
ff_videotoolbox_vpcc_extradata_create(AVCodecContext *avctx)62 CFDataRef ff_videotoolbox_vpcc_extradata_create(AVCodecContext *avctx)
63 {
64     const VP9SharedContext *h = avctx->priv_data;
65     CFDataRef data = NULL;
66     uint8_t *p;
67     int vt_extradata_size;
68     uint8_t *vt_extradata;
69     int subsampling = get_vpx_chroma_subsampling(avctx->sw_pix_fmt, avctx->chroma_sample_location);
70 
71     vt_extradata_size = 1 + 3 + 6 + 2;
72     vt_extradata = av_malloc(vt_extradata_size);
73 
74     if (subsampling < 0)
75         return NULL;
76 
77     if (!vt_extradata)
78         return NULL;
79 
80     p = vt_extradata;
81 
82     *p++ = 1; /* version */
83     AV_WB24(p + 1, 0); /* flags */
84     p += 3;
85 
86    *p++ = h->h.profile;
87    *p++ = avctx->level;
88    *p++ = (h->h.bpp << 4) | (subsampling << 1) | (avctx->color_range == AVCOL_RANGE_JPEG);
89    *p++ = avctx->color_primaries;
90    *p++ = avctx->color_trc;
91    *p++ = avctx->colorspace;
92 
93     AV_WB16(p + 0, 0);
94     p += 2;
95 
96     av_assert0(p - vt_extradata == vt_extradata_size);
97 
98     data = CFDataCreate(kCFAllocatorDefault, vt_extradata, vt_extradata_size);
99     av_free(vt_extradata);
100     return data;
101 }
102 
videotoolbox_vp9_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)103 static int videotoolbox_vp9_start_frame(AVCodecContext *avctx,
104                                         const uint8_t *buffer,
105                                         uint32_t size)
106 {
107     return 0;
108 }
109 
videotoolbox_vp9_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size)110 static int videotoolbox_vp9_decode_slice(AVCodecContext *avctx,
111                                          const uint8_t *buffer,
112                                          uint32_t size)
113 {
114     VTContext *vtctx = avctx->internal->hwaccel_priv_data;
115 
116     return ff_videotoolbox_buffer_copy(vtctx, buffer, size);
117 }
118 
videotoolbox_vp9_end_frame(AVCodecContext *avctx)119 static int videotoolbox_vp9_end_frame(AVCodecContext *avctx)
120 {
121     const VP9SharedContext *h = avctx->priv_data;
122     AVFrame *frame = h->frames[CUR_FRAME].tf.f;
123 
124     return ff_videotoolbox_common_end_frame(avctx, frame);
125 }
126 
127 const AVHWAccel ff_vp9_videotoolbox_hwaccel = {
128     .name           = "vp9_videotoolbox",
129     .type           = AVMEDIA_TYPE_VIDEO,
130     .id             = AV_CODEC_ID_VP9,
131     .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
132     .alloc_frame    = ff_videotoolbox_alloc_frame,
133     .start_frame    = videotoolbox_vp9_start_frame,
134     .decode_slice   = videotoolbox_vp9_decode_slice,
135     .end_frame      = videotoolbox_vp9_end_frame,
136     .frame_params   = ff_videotoolbox_frame_params,
137     .init           = ff_videotoolbox_common_init,
138     .uninit         = ff_videotoolbox_uninit,
139     .priv_data_size = sizeof(VTContext),
140 };
141