1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Videotoolbox hardware acceleration
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * copyright (c) 2012 Sebastien Zwickert
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * This file is part of FFmpeg.
7cabdff1aSopenharmony_ci *
8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
12cabdff1aSopenharmony_ci *
13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16cabdff1aSopenharmony_ci * Lesser General Public License for more details.
17cabdff1aSopenharmony_ci *
18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21cabdff1aSopenharmony_ci */
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include "config.h"
24cabdff1aSopenharmony_ci#include "config_components.h"
25cabdff1aSopenharmony_ci#include "videotoolbox.h"
26cabdff1aSopenharmony_ci#include "libavutil/hwcontext_videotoolbox.h"
27cabdff1aSopenharmony_ci#include "vt_internal.h"
28cabdff1aSopenharmony_ci#include "libavutil/avutil.h"
29cabdff1aSopenharmony_ci#include "libavutil/hwcontext.h"
30cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h"
31cabdff1aSopenharmony_ci#include "bytestream.h"
32cabdff1aSopenharmony_ci#include "decode.h"
33cabdff1aSopenharmony_ci#include "internal.h"
34cabdff1aSopenharmony_ci#include "h264dec.h"
35cabdff1aSopenharmony_ci#include "hevcdec.h"
36cabdff1aSopenharmony_ci#include "mpegvideo.h"
37cabdff1aSopenharmony_ci#include "proresdec.h"
38cabdff1aSopenharmony_ci#include <Availability.h>
39cabdff1aSopenharmony_ci#include <AvailabilityMacros.h>
40cabdff1aSopenharmony_ci#include <TargetConditionals.h>
41cabdff1aSopenharmony_ci
42cabdff1aSopenharmony_ci#ifndef kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder
43cabdff1aSopenharmony_ci#  define kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder CFSTR("RequireHardwareAcceleratedVideoDecoder")
44cabdff1aSopenharmony_ci#endif
45cabdff1aSopenharmony_ci#ifndef kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder
46cabdff1aSopenharmony_ci#  define kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder CFSTR("EnableHardwareAcceleratedVideoDecoder")
47cabdff1aSopenharmony_ci#endif
48cabdff1aSopenharmony_ci
49cabdff1aSopenharmony_ci#if !HAVE_KCMVIDEOCODECTYPE_HEVC
50cabdff1aSopenharmony_cienum { kCMVideoCodecType_HEVC = 'hvc1' };
51cabdff1aSopenharmony_ci#endif
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_ci#if !HAVE_KCMVIDEOCODECTYPE_VP9
54cabdff1aSopenharmony_cienum { kCMVideoCodecType_VP9 = 'vp09' };
55cabdff1aSopenharmony_ci#endif
56cabdff1aSopenharmony_ci
57cabdff1aSopenharmony_ci#define VIDEOTOOLBOX_ESDS_EXTRADATA_PADDING  12
58cabdff1aSopenharmony_ci
59cabdff1aSopenharmony_citypedef struct VTHWFrame {
60cabdff1aSopenharmony_ci    CVPixelBufferRef pixbuf;
61cabdff1aSopenharmony_ci    AVBufferRef *hw_frames_ctx;
62cabdff1aSopenharmony_ci} VTHWFrame;
63cabdff1aSopenharmony_ci
64cabdff1aSopenharmony_cistatic void videotoolbox_buffer_release(void *opaque, uint8_t *data)
65cabdff1aSopenharmony_ci{
66cabdff1aSopenharmony_ci    VTHWFrame *ref = (VTHWFrame *)data;
67cabdff1aSopenharmony_ci    av_buffer_unref(&ref->hw_frames_ctx);
68cabdff1aSopenharmony_ci    CVPixelBufferRelease(ref->pixbuf);
69cabdff1aSopenharmony_ci
70cabdff1aSopenharmony_ci    av_free(data);
71cabdff1aSopenharmony_ci}
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_ciint ff_videotoolbox_buffer_copy(VTContext *vtctx,
74cabdff1aSopenharmony_ci                                const uint8_t *buffer,
75cabdff1aSopenharmony_ci                                uint32_t size)
76cabdff1aSopenharmony_ci{
77cabdff1aSopenharmony_ci    void *tmp;
78cabdff1aSopenharmony_ci
79cabdff1aSopenharmony_ci    tmp = av_fast_realloc(vtctx->bitstream,
80cabdff1aSopenharmony_ci                         &vtctx->allocated_size,
81cabdff1aSopenharmony_ci                         size);
82cabdff1aSopenharmony_ci
83cabdff1aSopenharmony_ci    if (!tmp)
84cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
85cabdff1aSopenharmony_ci
86cabdff1aSopenharmony_ci    vtctx->bitstream = tmp;
87cabdff1aSopenharmony_ci    memcpy(vtctx->bitstream, buffer, size);
88cabdff1aSopenharmony_ci    vtctx->bitstream_size = size;
89cabdff1aSopenharmony_ci
90cabdff1aSopenharmony_ci    return 0;
91cabdff1aSopenharmony_ci}
92cabdff1aSopenharmony_ci
93cabdff1aSopenharmony_cistatic int videotoolbox_postproc_frame(void *avctx, AVFrame *frame)
94cabdff1aSopenharmony_ci{
95cabdff1aSopenharmony_ci    int ret;
96cabdff1aSopenharmony_ci    VTHWFrame *ref = (VTHWFrame *)frame->buf[0]->data;
97cabdff1aSopenharmony_ci
98cabdff1aSopenharmony_ci    if (!ref->pixbuf) {
99cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "No frame decoded?\n");
100cabdff1aSopenharmony_ci        av_frame_unref(frame);
101cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
102cabdff1aSopenharmony_ci    }
103cabdff1aSopenharmony_ci
104cabdff1aSopenharmony_ci    frame->crop_right = 0;
105cabdff1aSopenharmony_ci    frame->crop_left = 0;
106cabdff1aSopenharmony_ci    frame->crop_top = 0;
107cabdff1aSopenharmony_ci    frame->crop_bottom = 0;
108cabdff1aSopenharmony_ci
109cabdff1aSopenharmony_ci    if ((ret = av_vt_pixbuf_set_attachments(avctx, ref->pixbuf, frame)) < 0)
110cabdff1aSopenharmony_ci        return ret;
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_ci    frame->data[3] = (uint8_t*)ref->pixbuf;
113cabdff1aSopenharmony_ci
114cabdff1aSopenharmony_ci    if (ref->hw_frames_ctx) {
115cabdff1aSopenharmony_ci        av_buffer_unref(&frame->hw_frames_ctx);
116cabdff1aSopenharmony_ci        frame->hw_frames_ctx = av_buffer_ref(ref->hw_frames_ctx);
117cabdff1aSopenharmony_ci        if (!frame->hw_frames_ctx)
118cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
119cabdff1aSopenharmony_ci    }
120cabdff1aSopenharmony_ci
121cabdff1aSopenharmony_ci    return 0;
122cabdff1aSopenharmony_ci}
123cabdff1aSopenharmony_ci
124cabdff1aSopenharmony_ciint ff_videotoolbox_alloc_frame(AVCodecContext *avctx, AVFrame *frame)
125cabdff1aSopenharmony_ci{
126cabdff1aSopenharmony_ci    size_t      size = sizeof(VTHWFrame);
127cabdff1aSopenharmony_ci    uint8_t    *data = NULL;
128cabdff1aSopenharmony_ci    AVBufferRef *buf = NULL;
129cabdff1aSopenharmony_ci    int ret = ff_attach_decode_data(frame);
130cabdff1aSopenharmony_ci    FrameDecodeData *fdd;
131cabdff1aSopenharmony_ci    if (ret < 0)
132cabdff1aSopenharmony_ci        return ret;
133cabdff1aSopenharmony_ci
134cabdff1aSopenharmony_ci    data = av_mallocz(size);
135cabdff1aSopenharmony_ci    if (!data)
136cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
137cabdff1aSopenharmony_ci    buf = av_buffer_create(data, size, videotoolbox_buffer_release, NULL, 0);
138cabdff1aSopenharmony_ci    if (!buf) {
139cabdff1aSopenharmony_ci        av_freep(&data);
140cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
141cabdff1aSopenharmony_ci    }
142cabdff1aSopenharmony_ci    frame->buf[0] = buf;
143cabdff1aSopenharmony_ci
144cabdff1aSopenharmony_ci    fdd = (FrameDecodeData*)frame->private_ref->data;
145cabdff1aSopenharmony_ci    fdd->post_process = videotoolbox_postproc_frame;
146cabdff1aSopenharmony_ci
147cabdff1aSopenharmony_ci    frame->width  = avctx->width;
148cabdff1aSopenharmony_ci    frame->height = avctx->height;
149cabdff1aSopenharmony_ci    frame->format = avctx->pix_fmt;
150cabdff1aSopenharmony_ci
151cabdff1aSopenharmony_ci    return 0;
152cabdff1aSopenharmony_ci}
153cabdff1aSopenharmony_ci
154cabdff1aSopenharmony_ci#define AV_W8(p, v) *(p) = (v)
155cabdff1aSopenharmony_ci
156cabdff1aSopenharmony_cistatic int escape_ps(uint8_t* dst, const uint8_t* src, int src_size)
157cabdff1aSopenharmony_ci{
158cabdff1aSopenharmony_ci    int i;
159cabdff1aSopenharmony_ci    int size = src_size;
160cabdff1aSopenharmony_ci    uint8_t* p = dst;
161cabdff1aSopenharmony_ci
162cabdff1aSopenharmony_ci    for (i = 0; i < src_size; i++) {
163cabdff1aSopenharmony_ci        if (i + 2 < src_size &&
164cabdff1aSopenharmony_ci            src[i]     == 0x00 &&
165cabdff1aSopenharmony_ci            src[i + 1] == 0x00 &&
166cabdff1aSopenharmony_ci            src[i + 2] <= 0x03) {
167cabdff1aSopenharmony_ci            if (dst) {
168cabdff1aSopenharmony_ci                *p++ = src[i++];
169cabdff1aSopenharmony_ci                *p++ = src[i];
170cabdff1aSopenharmony_ci                *p++ = 0x03;
171cabdff1aSopenharmony_ci            } else {
172cabdff1aSopenharmony_ci                i++;
173cabdff1aSopenharmony_ci            }
174cabdff1aSopenharmony_ci            size++;
175cabdff1aSopenharmony_ci        } else if (dst)
176cabdff1aSopenharmony_ci            *p++ = src[i];
177cabdff1aSopenharmony_ci    }
178cabdff1aSopenharmony_ci
179cabdff1aSopenharmony_ci    if (dst)
180cabdff1aSopenharmony_ci        av_assert0((p - dst) == size);
181cabdff1aSopenharmony_ci
182cabdff1aSopenharmony_ci    return size;
183cabdff1aSopenharmony_ci}
184cabdff1aSopenharmony_ci
185cabdff1aSopenharmony_ciCFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx)
186cabdff1aSopenharmony_ci{
187cabdff1aSopenharmony_ci    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
188cabdff1aSopenharmony_ci    H264Context *h = avctx->priv_data;
189cabdff1aSopenharmony_ci    CFDataRef data = NULL;
190cabdff1aSopenharmony_ci    uint8_t *p;
191cabdff1aSopenharmony_ci    int sps_size = escape_ps(NULL, h->ps.sps->data, h->ps.sps->data_size);
192cabdff1aSopenharmony_ci    int pps_size = escape_ps(NULL, h->ps.pps->data, h->ps.pps->data_size);
193cabdff1aSopenharmony_ci    int vt_extradata_size;
194cabdff1aSopenharmony_ci    uint8_t *vt_extradata;
195cabdff1aSopenharmony_ci
196cabdff1aSopenharmony_ci    vt_extradata_size = 6 + 2 + sps_size + 3 + pps_size;
197cabdff1aSopenharmony_ci    vt_extradata = av_malloc(vt_extradata_size);
198cabdff1aSopenharmony_ci
199cabdff1aSopenharmony_ci    if (!vt_extradata)
200cabdff1aSopenharmony_ci        return NULL;
201cabdff1aSopenharmony_ci
202cabdff1aSopenharmony_ci    p = vt_extradata;
203cabdff1aSopenharmony_ci
204cabdff1aSopenharmony_ci    AV_W8(p + 0, 1); /* version */
205cabdff1aSopenharmony_ci    AV_W8(p + 1, h->ps.sps->data[1]); /* profile */
206cabdff1aSopenharmony_ci    AV_W8(p + 2, h->ps.sps->data[2]); /* profile compat */
207cabdff1aSopenharmony_ci    AV_W8(p + 3, h->ps.sps->data[3]); /* level */
208cabdff1aSopenharmony_ci    AV_W8(p + 4, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 3 (11) */
209cabdff1aSopenharmony_ci    AV_W8(p + 5, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */
210cabdff1aSopenharmony_ci    AV_WB16(p + 6, sps_size);
211cabdff1aSopenharmony_ci    p += 8;
212cabdff1aSopenharmony_ci    p += escape_ps(p, h->ps.sps->data, h->ps.sps->data_size);
213cabdff1aSopenharmony_ci    AV_W8(p + 0, 1); /* number of pps */
214cabdff1aSopenharmony_ci    AV_WB16(p + 1, pps_size);
215cabdff1aSopenharmony_ci    p += 3;
216cabdff1aSopenharmony_ci    p += escape_ps(p, h->ps.pps->data, h->ps.pps->data_size);
217cabdff1aSopenharmony_ci
218cabdff1aSopenharmony_ci    av_assert0(p - vt_extradata == vt_extradata_size);
219cabdff1aSopenharmony_ci
220cabdff1aSopenharmony_ci    // save sps header (profile/level) used to create decoder session,
221cabdff1aSopenharmony_ci    // so we can detect changes and recreate it.
222cabdff1aSopenharmony_ci    if (vtctx)
223cabdff1aSopenharmony_ci        memcpy(vtctx->sps, h->ps.sps->data + 1, 3);
224cabdff1aSopenharmony_ci
225cabdff1aSopenharmony_ci    data = CFDataCreate(kCFAllocatorDefault, vt_extradata, vt_extradata_size);
226cabdff1aSopenharmony_ci    av_free(vt_extradata);
227cabdff1aSopenharmony_ci    return data;
228cabdff1aSopenharmony_ci}
229cabdff1aSopenharmony_ci
230cabdff1aSopenharmony_ciCFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx)
231cabdff1aSopenharmony_ci{
232cabdff1aSopenharmony_ci    HEVCContext *h = avctx->priv_data;
233cabdff1aSopenharmony_ci    int i, num_vps = 0, num_sps = 0, num_pps = 0;
234cabdff1aSopenharmony_ci    const HEVCVPS *vps = h->ps.vps;
235cabdff1aSopenharmony_ci    const HEVCSPS *sps = h->ps.sps;
236cabdff1aSopenharmony_ci    const HEVCPPS *pps = h->ps.pps;
237cabdff1aSopenharmony_ci    PTLCommon ptlc = vps->ptl.general_ptl;
238cabdff1aSopenharmony_ci    VUI vui = sps->vui;
239cabdff1aSopenharmony_ci    uint8_t parallelismType;
240cabdff1aSopenharmony_ci    CFDataRef data = NULL;
241cabdff1aSopenharmony_ci    uint8_t *p;
242cabdff1aSopenharmony_ci    int vt_extradata_size = 23 + 3 + 3 + 3;
243cabdff1aSopenharmony_ci    uint8_t *vt_extradata;
244cabdff1aSopenharmony_ci
245cabdff1aSopenharmony_ci#define COUNT_SIZE_PS(T, t) \
246cabdff1aSopenharmony_ci    for (i = 0; i < HEVC_MAX_##T##PS_COUNT; i++) { \
247cabdff1aSopenharmony_ci        if (h->ps.t##ps_list[i]) { \
248cabdff1aSopenharmony_ci            const HEVC##T##PS *lps = (const HEVC##T##PS *)h->ps.t##ps_list[i]->data; \
249cabdff1aSopenharmony_ci            vt_extradata_size += 2 + escape_ps(NULL, lps->data, lps->data_size); \
250cabdff1aSopenharmony_ci            num_##t##ps++; \
251cabdff1aSopenharmony_ci        } \
252cabdff1aSopenharmony_ci    }
253cabdff1aSopenharmony_ci
254cabdff1aSopenharmony_ci    COUNT_SIZE_PS(V, v)
255cabdff1aSopenharmony_ci    COUNT_SIZE_PS(S, s)
256cabdff1aSopenharmony_ci    COUNT_SIZE_PS(P, p)
257cabdff1aSopenharmony_ci
258cabdff1aSopenharmony_ci    vt_extradata = av_malloc(vt_extradata_size);
259cabdff1aSopenharmony_ci    if (!vt_extradata)
260cabdff1aSopenharmony_ci        return NULL;
261cabdff1aSopenharmony_ci    p = vt_extradata;
262cabdff1aSopenharmony_ci
263cabdff1aSopenharmony_ci    /* unsigned int(8) configurationVersion = 1; */
264cabdff1aSopenharmony_ci    AV_W8(p + 0, 1);
265cabdff1aSopenharmony_ci
266cabdff1aSopenharmony_ci    /*
267cabdff1aSopenharmony_ci     * unsigned int(2) general_profile_space;
268cabdff1aSopenharmony_ci     * unsigned int(1) general_tier_flag;
269cabdff1aSopenharmony_ci     * unsigned int(5) general_profile_idc;
270cabdff1aSopenharmony_ci     */
271cabdff1aSopenharmony_ci    AV_W8(p + 1, ptlc.profile_space << 6 |
272cabdff1aSopenharmony_ci                 ptlc.tier_flag     << 5 |
273cabdff1aSopenharmony_ci                 ptlc.profile_idc);
274cabdff1aSopenharmony_ci
275cabdff1aSopenharmony_ci    /* unsigned int(32) general_profile_compatibility_flags; */
276cabdff1aSopenharmony_ci    for (i = 0; i < 4; i++) {
277cabdff1aSopenharmony_ci        AV_W8(p + 2 + i, ptlc.profile_compatibility_flag[i * 8] << 7 |
278cabdff1aSopenharmony_ci                         ptlc.profile_compatibility_flag[i * 8 + 1] << 6 |
279cabdff1aSopenharmony_ci                         ptlc.profile_compatibility_flag[i * 8 + 2] << 5 |
280cabdff1aSopenharmony_ci                         ptlc.profile_compatibility_flag[i * 8 + 3] << 4 |
281cabdff1aSopenharmony_ci                         ptlc.profile_compatibility_flag[i * 8 + 4] << 3 |
282cabdff1aSopenharmony_ci                         ptlc.profile_compatibility_flag[i * 8 + 5] << 2 |
283cabdff1aSopenharmony_ci                         ptlc.profile_compatibility_flag[i * 8 + 6] << 1 |
284cabdff1aSopenharmony_ci                         ptlc.profile_compatibility_flag[i * 8 + 7]);
285cabdff1aSopenharmony_ci    }
286cabdff1aSopenharmony_ci
287cabdff1aSopenharmony_ci    /* unsigned int(48) general_constraint_indicator_flags; */
288cabdff1aSopenharmony_ci    AV_W8(p + 6, ptlc.progressive_source_flag    << 7 |
289cabdff1aSopenharmony_ci                 ptlc.interlaced_source_flag     << 6 |
290cabdff1aSopenharmony_ci                 ptlc.non_packed_constraint_flag << 5 |
291cabdff1aSopenharmony_ci                 ptlc.frame_only_constraint_flag << 4);
292cabdff1aSopenharmony_ci    AV_W8(p + 7, 0);
293cabdff1aSopenharmony_ci    AV_WN32(p + 8, 0);
294cabdff1aSopenharmony_ci
295cabdff1aSopenharmony_ci    /* unsigned int(8) general_level_idc; */
296cabdff1aSopenharmony_ci    AV_W8(p + 12, ptlc.level_idc);
297cabdff1aSopenharmony_ci
298cabdff1aSopenharmony_ci    /*
299cabdff1aSopenharmony_ci     * bit(4) reserved = ‘1111’b;
300cabdff1aSopenharmony_ci     * unsigned int(12) min_spatial_segmentation_idc;
301cabdff1aSopenharmony_ci     */
302cabdff1aSopenharmony_ci    AV_W8(p + 13, 0xf0 | (vui.min_spatial_segmentation_idc >> 4));
303cabdff1aSopenharmony_ci    AV_W8(p + 14, vui.min_spatial_segmentation_idc & 0xff);
304cabdff1aSopenharmony_ci
305cabdff1aSopenharmony_ci    /*
306cabdff1aSopenharmony_ci     * bit(6) reserved = ‘111111’b;
307cabdff1aSopenharmony_ci     * unsigned int(2) parallelismType;
308cabdff1aSopenharmony_ci     */
309cabdff1aSopenharmony_ci    if (!vui.min_spatial_segmentation_idc)
310cabdff1aSopenharmony_ci        parallelismType = 0;
311cabdff1aSopenharmony_ci    else if (pps->entropy_coding_sync_enabled_flag && pps->tiles_enabled_flag)
312cabdff1aSopenharmony_ci        parallelismType = 0;
313cabdff1aSopenharmony_ci    else if (pps->entropy_coding_sync_enabled_flag)
314cabdff1aSopenharmony_ci        parallelismType = 3;
315cabdff1aSopenharmony_ci    else if (pps->tiles_enabled_flag)
316cabdff1aSopenharmony_ci        parallelismType = 2;
317cabdff1aSopenharmony_ci    else
318cabdff1aSopenharmony_ci        parallelismType = 1;
319cabdff1aSopenharmony_ci    AV_W8(p + 15, 0xfc | parallelismType);
320cabdff1aSopenharmony_ci
321cabdff1aSopenharmony_ci    /*
322cabdff1aSopenharmony_ci     * bit(6) reserved = ‘111111’b;
323cabdff1aSopenharmony_ci     * unsigned int(2) chromaFormat;
324cabdff1aSopenharmony_ci     */
325cabdff1aSopenharmony_ci    AV_W8(p + 16, sps->chroma_format_idc | 0xfc);
326cabdff1aSopenharmony_ci
327cabdff1aSopenharmony_ci    /*
328cabdff1aSopenharmony_ci     * bit(5) reserved = ‘11111’b;
329cabdff1aSopenharmony_ci     * unsigned int(3) bitDepthLumaMinus8;
330cabdff1aSopenharmony_ci     */
331cabdff1aSopenharmony_ci    AV_W8(p + 17, (sps->bit_depth - 8) | 0xf8);
332cabdff1aSopenharmony_ci
333cabdff1aSopenharmony_ci    /*
334cabdff1aSopenharmony_ci     * bit(5) reserved = ‘11111’b;
335cabdff1aSopenharmony_ci     * unsigned int(3) bitDepthChromaMinus8;
336cabdff1aSopenharmony_ci     */
337cabdff1aSopenharmony_ci    AV_W8(p + 18, (sps->bit_depth_chroma - 8) | 0xf8);
338cabdff1aSopenharmony_ci
339cabdff1aSopenharmony_ci    /* bit(16) avgFrameRate; */
340cabdff1aSopenharmony_ci    AV_WB16(p + 19, 0);
341cabdff1aSopenharmony_ci
342cabdff1aSopenharmony_ci    /*
343cabdff1aSopenharmony_ci     * bit(2) constantFrameRate;
344cabdff1aSopenharmony_ci     * bit(3) numTemporalLayers;
345cabdff1aSopenharmony_ci     * bit(1) temporalIdNested;
346cabdff1aSopenharmony_ci     * unsigned int(2) lengthSizeMinusOne;
347cabdff1aSopenharmony_ci     */
348cabdff1aSopenharmony_ci    AV_W8(p + 21, 0                             << 6 |
349cabdff1aSopenharmony_ci                  sps->max_sub_layers           << 3 |
350cabdff1aSopenharmony_ci                  sps->temporal_id_nesting_flag << 2 |
351cabdff1aSopenharmony_ci                  3);
352cabdff1aSopenharmony_ci
353cabdff1aSopenharmony_ci    /* unsigned int(8) numOfArrays; */
354cabdff1aSopenharmony_ci    AV_W8(p + 22, 3);
355cabdff1aSopenharmony_ci
356cabdff1aSopenharmony_ci    p += 23;
357cabdff1aSopenharmony_ci
358cabdff1aSopenharmony_ci#define APPEND_PS(T, t) \
359cabdff1aSopenharmony_ci    /* \
360cabdff1aSopenharmony_ci     * bit(1) array_completeness; \
361cabdff1aSopenharmony_ci     * unsigned int(1) reserved = 0; \
362cabdff1aSopenharmony_ci     * unsigned int(6) NAL_unit_type; \
363cabdff1aSopenharmony_ci     */ \
364cabdff1aSopenharmony_ci    AV_W8(p, 1 << 7 | \
365cabdff1aSopenharmony_ci             HEVC_NAL_##T##PS & 0x3f); \
366cabdff1aSopenharmony_ci    /* unsigned int(16) numNalus; */ \
367cabdff1aSopenharmony_ci    AV_WB16(p + 1, num_##t##ps); \
368cabdff1aSopenharmony_ci    p += 3; \
369cabdff1aSopenharmony_ci    for (i = 0; i < HEVC_MAX_##T##PS_COUNT; i++) { \
370cabdff1aSopenharmony_ci        if (h->ps.t##ps_list[i]) { \
371cabdff1aSopenharmony_ci            const HEVC##T##PS *lps = (const HEVC##T##PS *)h->ps.t##ps_list[i]->data; \
372cabdff1aSopenharmony_ci            int size = escape_ps(p + 2, lps->data, lps->data_size); \
373cabdff1aSopenharmony_ci            /* unsigned int(16) nalUnitLength; */ \
374cabdff1aSopenharmony_ci            AV_WB16(p, size); \
375cabdff1aSopenharmony_ci            /* bit(8*nalUnitLength) nalUnit; */ \
376cabdff1aSopenharmony_ci            p += 2 + size; \
377cabdff1aSopenharmony_ci        } \
378cabdff1aSopenharmony_ci    }
379cabdff1aSopenharmony_ci
380cabdff1aSopenharmony_ci    APPEND_PS(V, v)
381cabdff1aSopenharmony_ci    APPEND_PS(S, s)
382cabdff1aSopenharmony_ci    APPEND_PS(P, p)
383cabdff1aSopenharmony_ci
384cabdff1aSopenharmony_ci    av_assert0(p - vt_extradata == vt_extradata_size);
385cabdff1aSopenharmony_ci
386cabdff1aSopenharmony_ci    data = CFDataCreate(kCFAllocatorDefault, vt_extradata, vt_extradata_size);
387cabdff1aSopenharmony_ci    av_free(vt_extradata);
388cabdff1aSopenharmony_ci    return data;
389cabdff1aSopenharmony_ci}
390cabdff1aSopenharmony_ci
391cabdff1aSopenharmony_ciint ff_videotoolbox_h264_start_frame(AVCodecContext *avctx,
392cabdff1aSopenharmony_ci                                     const uint8_t *buffer,
393cabdff1aSopenharmony_ci                                     uint32_t size)
394cabdff1aSopenharmony_ci{
395cabdff1aSopenharmony_ci    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
396cabdff1aSopenharmony_ci    H264Context *h = avctx->priv_data;
397cabdff1aSopenharmony_ci
398cabdff1aSopenharmony_ci    if (h->is_avc == 1) {
399cabdff1aSopenharmony_ci        return ff_videotoolbox_buffer_copy(vtctx, buffer, size);
400cabdff1aSopenharmony_ci    }
401cabdff1aSopenharmony_ci
402cabdff1aSopenharmony_ci    return 0;
403cabdff1aSopenharmony_ci}
404cabdff1aSopenharmony_ci
405cabdff1aSopenharmony_cistatic int videotoolbox_h264_decode_params(AVCodecContext *avctx,
406cabdff1aSopenharmony_ci                                           int type,
407cabdff1aSopenharmony_ci                                           const uint8_t *buffer,
408cabdff1aSopenharmony_ci                                           uint32_t size)
409cabdff1aSopenharmony_ci{
410cabdff1aSopenharmony_ci    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
411cabdff1aSopenharmony_ci    H264Context *h = avctx->priv_data;
412cabdff1aSopenharmony_ci
413cabdff1aSopenharmony_ci    // save sps header (profile/level) used to create decoder session
414cabdff1aSopenharmony_ci    if (!vtctx->sps[0])
415cabdff1aSopenharmony_ci        memcpy(vtctx->sps, h->ps.sps->data + 1, 3);
416cabdff1aSopenharmony_ci
417cabdff1aSopenharmony_ci    if (type == H264_NAL_SPS) {
418cabdff1aSopenharmony_ci        if (size > 4 && memcmp(vtctx->sps, buffer + 1, 3) != 0) {
419cabdff1aSopenharmony_ci            vtctx->reconfig_needed = true;
420cabdff1aSopenharmony_ci            memcpy(vtctx->sps, buffer + 1, 3);
421cabdff1aSopenharmony_ci        }
422cabdff1aSopenharmony_ci    }
423cabdff1aSopenharmony_ci
424cabdff1aSopenharmony_ci    // pass-through SPS/PPS changes to the decoder
425cabdff1aSopenharmony_ci    return ff_videotoolbox_h264_decode_slice(avctx, buffer, size);
426cabdff1aSopenharmony_ci}
427cabdff1aSopenharmony_ci
428cabdff1aSopenharmony_cistatic int videotoolbox_common_decode_slice(AVCodecContext *avctx,
429cabdff1aSopenharmony_ci                                            const uint8_t *buffer,
430cabdff1aSopenharmony_ci                                            uint32_t size)
431cabdff1aSopenharmony_ci{
432cabdff1aSopenharmony_ci    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
433cabdff1aSopenharmony_ci    void *tmp;
434cabdff1aSopenharmony_ci
435cabdff1aSopenharmony_ci    tmp = av_fast_realloc(vtctx->bitstream,
436cabdff1aSopenharmony_ci                          &vtctx->allocated_size,
437cabdff1aSopenharmony_ci                          vtctx->bitstream_size+size+4);
438cabdff1aSopenharmony_ci    if (!tmp)
439cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
440cabdff1aSopenharmony_ci
441cabdff1aSopenharmony_ci    vtctx->bitstream = tmp;
442cabdff1aSopenharmony_ci
443cabdff1aSopenharmony_ci    AV_WB32(vtctx->bitstream + vtctx->bitstream_size, size);
444cabdff1aSopenharmony_ci    memcpy(vtctx->bitstream + vtctx->bitstream_size + 4, buffer, size);
445cabdff1aSopenharmony_ci
446cabdff1aSopenharmony_ci    vtctx->bitstream_size += size + 4;
447cabdff1aSopenharmony_ci
448cabdff1aSopenharmony_ci    return 0;
449cabdff1aSopenharmony_ci}
450cabdff1aSopenharmony_ci
451cabdff1aSopenharmony_ciint ff_videotoolbox_h264_decode_slice(AVCodecContext *avctx,
452cabdff1aSopenharmony_ci                                      const uint8_t *buffer,
453cabdff1aSopenharmony_ci                                      uint32_t size)
454cabdff1aSopenharmony_ci{
455cabdff1aSopenharmony_ci    H264Context *h = avctx->priv_data;
456cabdff1aSopenharmony_ci
457cabdff1aSopenharmony_ci    if (h->is_avc == 1)
458cabdff1aSopenharmony_ci        return 0;
459cabdff1aSopenharmony_ci
460cabdff1aSopenharmony_ci    return videotoolbox_common_decode_slice(avctx, buffer, size);
461cabdff1aSopenharmony_ci}
462cabdff1aSopenharmony_ci
463cabdff1aSopenharmony_ci#if CONFIG_VIDEOTOOLBOX
464cabdff1aSopenharmony_ci// Return the AVVideotoolboxContext that matters currently. Where it comes from
465cabdff1aSopenharmony_ci// depends on the API used.
466cabdff1aSopenharmony_cistatic AVVideotoolboxContext *videotoolbox_get_context(AVCodecContext *avctx)
467cabdff1aSopenharmony_ci{
468cabdff1aSopenharmony_ci    // Somewhat tricky because the user can call av_videotoolbox_default_free()
469cabdff1aSopenharmony_ci    // at any time, even when the codec is closed.
470cabdff1aSopenharmony_ci    if (avctx->internal && avctx->internal->hwaccel_priv_data) {
471cabdff1aSopenharmony_ci        VTContext *vtctx = avctx->internal->hwaccel_priv_data;
472cabdff1aSopenharmony_ci        if (vtctx->vt_ctx)
473cabdff1aSopenharmony_ci            return vtctx->vt_ctx;
474cabdff1aSopenharmony_ci    }
475cabdff1aSopenharmony_ci    return avctx->hwaccel_context;
476cabdff1aSopenharmony_ci}
477cabdff1aSopenharmony_ci
478cabdff1aSopenharmony_cistatic void videotoolbox_stop(AVCodecContext *avctx)
479cabdff1aSopenharmony_ci{
480cabdff1aSopenharmony_ci    AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx);
481cabdff1aSopenharmony_ci    if (!videotoolbox)
482cabdff1aSopenharmony_ci        return;
483cabdff1aSopenharmony_ci
484cabdff1aSopenharmony_ci    if (videotoolbox->cm_fmt_desc) {
485cabdff1aSopenharmony_ci        CFRelease(videotoolbox->cm_fmt_desc);
486cabdff1aSopenharmony_ci        videotoolbox->cm_fmt_desc = NULL;
487cabdff1aSopenharmony_ci    }
488cabdff1aSopenharmony_ci
489cabdff1aSopenharmony_ci    if (videotoolbox->session) {
490cabdff1aSopenharmony_ci        VTDecompressionSessionInvalidate(videotoolbox->session);
491cabdff1aSopenharmony_ci        CFRelease(videotoolbox->session);
492cabdff1aSopenharmony_ci        videotoolbox->session = NULL;
493cabdff1aSopenharmony_ci    }
494cabdff1aSopenharmony_ci}
495cabdff1aSopenharmony_ci
496cabdff1aSopenharmony_ciint ff_videotoolbox_uninit(AVCodecContext *avctx)
497cabdff1aSopenharmony_ci{
498cabdff1aSopenharmony_ci    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
499cabdff1aSopenharmony_ci    if (!vtctx)
500cabdff1aSopenharmony_ci        return 0;
501cabdff1aSopenharmony_ci
502cabdff1aSopenharmony_ci    av_freep(&vtctx->bitstream);
503cabdff1aSopenharmony_ci    if (vtctx->frame)
504cabdff1aSopenharmony_ci        CVPixelBufferRelease(vtctx->frame);
505cabdff1aSopenharmony_ci
506cabdff1aSopenharmony_ci    if (vtctx->vt_ctx)
507cabdff1aSopenharmony_ci        videotoolbox_stop(avctx);
508cabdff1aSopenharmony_ci
509cabdff1aSopenharmony_ci    av_buffer_unref(&vtctx->cached_hw_frames_ctx);
510cabdff1aSopenharmony_ci    av_freep(&vtctx->vt_ctx);
511cabdff1aSopenharmony_ci
512cabdff1aSopenharmony_ci    return 0;
513cabdff1aSopenharmony_ci}
514cabdff1aSopenharmony_ci
515cabdff1aSopenharmony_cistatic int videotoolbox_buffer_create(AVCodecContext *avctx, AVFrame *frame)
516cabdff1aSopenharmony_ci{
517cabdff1aSopenharmony_ci    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
518cabdff1aSopenharmony_ci    CVPixelBufferRef pixbuf = (CVPixelBufferRef)vtctx->frame;
519cabdff1aSopenharmony_ci    OSType pixel_format = CVPixelBufferGetPixelFormatType(pixbuf);
520cabdff1aSopenharmony_ci    enum AVPixelFormat sw_format = av_map_videotoolbox_format_to_pixfmt(pixel_format);
521cabdff1aSopenharmony_ci    int width = CVPixelBufferGetWidth(pixbuf);
522cabdff1aSopenharmony_ci    int height = CVPixelBufferGetHeight(pixbuf);
523cabdff1aSopenharmony_ci    AVHWFramesContext *cached_frames;
524cabdff1aSopenharmony_ci    VTHWFrame *ref;
525cabdff1aSopenharmony_ci    int ret;
526cabdff1aSopenharmony_ci
527cabdff1aSopenharmony_ci    if (!frame->buf[0] || frame->data[3]) {
528cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "videotoolbox: invalid state\n");
529cabdff1aSopenharmony_ci        av_frame_unref(frame);
530cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
531cabdff1aSopenharmony_ci    }
532cabdff1aSopenharmony_ci
533cabdff1aSopenharmony_ci    ref = (VTHWFrame *)frame->buf[0]->data;
534cabdff1aSopenharmony_ci
535cabdff1aSopenharmony_ci    if (ref->pixbuf)
536cabdff1aSopenharmony_ci        CVPixelBufferRelease(ref->pixbuf);
537cabdff1aSopenharmony_ci    ref->pixbuf = vtctx->frame;
538cabdff1aSopenharmony_ci    vtctx->frame = NULL;
539cabdff1aSopenharmony_ci
540cabdff1aSopenharmony_ci    // Old API code path.
541cabdff1aSopenharmony_ci    if (!vtctx->cached_hw_frames_ctx)
542cabdff1aSopenharmony_ci        return 0;
543cabdff1aSopenharmony_ci
544cabdff1aSopenharmony_ci    cached_frames = (AVHWFramesContext*)vtctx->cached_hw_frames_ctx->data;
545cabdff1aSopenharmony_ci
546cabdff1aSopenharmony_ci    if (cached_frames->sw_format != sw_format ||
547cabdff1aSopenharmony_ci        cached_frames->width != width ||
548cabdff1aSopenharmony_ci        cached_frames->height != height) {
549cabdff1aSopenharmony_ci        AVBufferRef *hw_frames_ctx = av_hwframe_ctx_alloc(cached_frames->device_ref);
550cabdff1aSopenharmony_ci        AVHWFramesContext *hw_frames;
551cabdff1aSopenharmony_ci        if (!hw_frames_ctx)
552cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
553cabdff1aSopenharmony_ci
554cabdff1aSopenharmony_ci        hw_frames = (AVHWFramesContext*)hw_frames_ctx->data;
555cabdff1aSopenharmony_ci        hw_frames->format = cached_frames->format;
556cabdff1aSopenharmony_ci        hw_frames->sw_format = sw_format;
557cabdff1aSopenharmony_ci        hw_frames->width = width;
558cabdff1aSopenharmony_ci        hw_frames->height = height;
559cabdff1aSopenharmony_ci
560cabdff1aSopenharmony_ci        ret = av_hwframe_ctx_init(hw_frames_ctx);
561cabdff1aSopenharmony_ci        if (ret < 0) {
562cabdff1aSopenharmony_ci            av_buffer_unref(&hw_frames_ctx);
563cabdff1aSopenharmony_ci            return ret;
564cabdff1aSopenharmony_ci        }
565cabdff1aSopenharmony_ci
566cabdff1aSopenharmony_ci        av_buffer_unref(&vtctx->cached_hw_frames_ctx);
567cabdff1aSopenharmony_ci        vtctx->cached_hw_frames_ctx = hw_frames_ctx;
568cabdff1aSopenharmony_ci    }
569cabdff1aSopenharmony_ci
570cabdff1aSopenharmony_ci    av_buffer_unref(&ref->hw_frames_ctx);
571cabdff1aSopenharmony_ci    ref->hw_frames_ctx = av_buffer_ref(vtctx->cached_hw_frames_ctx);
572cabdff1aSopenharmony_ci    if (!ref->hw_frames_ctx)
573cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
574cabdff1aSopenharmony_ci
575cabdff1aSopenharmony_ci    return 0;
576cabdff1aSopenharmony_ci}
577cabdff1aSopenharmony_ci
578cabdff1aSopenharmony_cistatic void videotoolbox_write_mp4_descr_length(PutByteContext *pb, int length)
579cabdff1aSopenharmony_ci{
580cabdff1aSopenharmony_ci    int i;
581cabdff1aSopenharmony_ci    uint8_t b;
582cabdff1aSopenharmony_ci
583cabdff1aSopenharmony_ci    for (i = 3; i >= 0; i--) {
584cabdff1aSopenharmony_ci        b = (length >> (i * 7)) & 0x7F;
585cabdff1aSopenharmony_ci        if (i != 0)
586cabdff1aSopenharmony_ci            b |= 0x80;
587cabdff1aSopenharmony_ci
588cabdff1aSopenharmony_ci        bytestream2_put_byteu(pb, b);
589cabdff1aSopenharmony_ci    }
590cabdff1aSopenharmony_ci}
591cabdff1aSopenharmony_ci
592cabdff1aSopenharmony_cistatic CFDataRef videotoolbox_esds_extradata_create(AVCodecContext *avctx)
593cabdff1aSopenharmony_ci{
594cabdff1aSopenharmony_ci    CFDataRef data;
595cabdff1aSopenharmony_ci    uint8_t *rw_extradata;
596cabdff1aSopenharmony_ci    PutByteContext pb;
597cabdff1aSopenharmony_ci    int full_size = 3 + 5 + 13 + 5 + avctx->extradata_size + 3;
598cabdff1aSopenharmony_ci    // ES_DescrTag data + DecoderConfigDescrTag + data + DecSpecificInfoTag + size + SLConfigDescriptor
599cabdff1aSopenharmony_ci    int config_size = 13 + 5 + avctx->extradata_size;
600cabdff1aSopenharmony_ci    int s;
601cabdff1aSopenharmony_ci
602cabdff1aSopenharmony_ci    if (!(rw_extradata = av_mallocz(full_size + VIDEOTOOLBOX_ESDS_EXTRADATA_PADDING)))
603cabdff1aSopenharmony_ci        return NULL;
604cabdff1aSopenharmony_ci
605cabdff1aSopenharmony_ci    bytestream2_init_writer(&pb, rw_extradata, full_size + VIDEOTOOLBOX_ESDS_EXTRADATA_PADDING);
606cabdff1aSopenharmony_ci    bytestream2_put_byteu(&pb, 0);        // version
607cabdff1aSopenharmony_ci    bytestream2_put_ne24(&pb, 0);         // flags
608cabdff1aSopenharmony_ci
609cabdff1aSopenharmony_ci    // elementary stream descriptor
610cabdff1aSopenharmony_ci    bytestream2_put_byteu(&pb, 0x03);     // ES_DescrTag
611cabdff1aSopenharmony_ci    videotoolbox_write_mp4_descr_length(&pb, full_size);
612cabdff1aSopenharmony_ci    bytestream2_put_ne16(&pb, 0);         // esid
613cabdff1aSopenharmony_ci    bytestream2_put_byteu(&pb, 0);        // stream priority (0-32)
614cabdff1aSopenharmony_ci
615cabdff1aSopenharmony_ci    // decoder configuration descriptor
616cabdff1aSopenharmony_ci    bytestream2_put_byteu(&pb, 0x04);     // DecoderConfigDescrTag
617cabdff1aSopenharmony_ci    videotoolbox_write_mp4_descr_length(&pb, config_size);
618cabdff1aSopenharmony_ci    bytestream2_put_byteu(&pb, 32);       // object type indication. 32 = AV_CODEC_ID_MPEG4
619cabdff1aSopenharmony_ci    bytestream2_put_byteu(&pb, 0x11);     // stream type
620cabdff1aSopenharmony_ci    bytestream2_put_ne24(&pb, 0);         // buffer size
621cabdff1aSopenharmony_ci    bytestream2_put_ne32(&pb, 0);         // max bitrate
622cabdff1aSopenharmony_ci    bytestream2_put_ne32(&pb, 0);         // avg bitrate
623cabdff1aSopenharmony_ci
624cabdff1aSopenharmony_ci    // decoder specific descriptor
625cabdff1aSopenharmony_ci    bytestream2_put_byteu(&pb, 0x05);     ///< DecSpecificInfoTag
626cabdff1aSopenharmony_ci    videotoolbox_write_mp4_descr_length(&pb, avctx->extradata_size);
627cabdff1aSopenharmony_ci
628cabdff1aSopenharmony_ci    bytestream2_put_buffer(&pb, avctx->extradata, avctx->extradata_size);
629cabdff1aSopenharmony_ci
630cabdff1aSopenharmony_ci    // SLConfigDescriptor
631cabdff1aSopenharmony_ci    bytestream2_put_byteu(&pb, 0x06);     // SLConfigDescrTag
632cabdff1aSopenharmony_ci    bytestream2_put_byteu(&pb, 0x01);     // length
633cabdff1aSopenharmony_ci    bytestream2_put_byteu(&pb, 0x02);     //
634cabdff1aSopenharmony_ci
635cabdff1aSopenharmony_ci    s = bytestream2_size_p(&pb);
636cabdff1aSopenharmony_ci
637cabdff1aSopenharmony_ci    data = CFDataCreate(kCFAllocatorDefault, rw_extradata, s);
638cabdff1aSopenharmony_ci
639cabdff1aSopenharmony_ci    av_freep(&rw_extradata);
640cabdff1aSopenharmony_ci    return data;
641cabdff1aSopenharmony_ci}
642cabdff1aSopenharmony_ci
643cabdff1aSopenharmony_cistatic CMSampleBufferRef videotoolbox_sample_buffer_create(CMFormatDescriptionRef fmt_desc,
644cabdff1aSopenharmony_ci                                                           void *buffer,
645cabdff1aSopenharmony_ci                                                           int size)
646cabdff1aSopenharmony_ci{
647cabdff1aSopenharmony_ci    OSStatus status;
648cabdff1aSopenharmony_ci    CMBlockBufferRef  block_buf;
649cabdff1aSopenharmony_ci    CMSampleBufferRef sample_buf;
650cabdff1aSopenharmony_ci
651cabdff1aSopenharmony_ci    block_buf  = NULL;
652cabdff1aSopenharmony_ci    sample_buf = NULL;
653cabdff1aSopenharmony_ci
654cabdff1aSopenharmony_ci    status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault,// structureAllocator
655cabdff1aSopenharmony_ci                                                buffer,             // memoryBlock
656cabdff1aSopenharmony_ci                                                size,               // blockLength
657cabdff1aSopenharmony_ci                                                kCFAllocatorNull,   // blockAllocator
658cabdff1aSopenharmony_ci                                                NULL,               // customBlockSource
659cabdff1aSopenharmony_ci                                                0,                  // offsetToData
660cabdff1aSopenharmony_ci                                                size,               // dataLength
661cabdff1aSopenharmony_ci                                                0,                  // flags
662cabdff1aSopenharmony_ci                                                &block_buf);
663cabdff1aSopenharmony_ci
664cabdff1aSopenharmony_ci    if (!status) {
665cabdff1aSopenharmony_ci        status = CMSampleBufferCreate(kCFAllocatorDefault,  // allocator
666cabdff1aSopenharmony_ci                                      block_buf,            // dataBuffer
667cabdff1aSopenharmony_ci                                      TRUE,                 // dataReady
668cabdff1aSopenharmony_ci                                      0,                    // makeDataReadyCallback
669cabdff1aSopenharmony_ci                                      0,                    // makeDataReadyRefcon
670cabdff1aSopenharmony_ci                                      fmt_desc,             // formatDescription
671cabdff1aSopenharmony_ci                                      1,                    // numSamples
672cabdff1aSopenharmony_ci                                      0,                    // numSampleTimingEntries
673cabdff1aSopenharmony_ci                                      NULL,                 // sampleTimingArray
674cabdff1aSopenharmony_ci                                      0,                    // numSampleSizeEntries
675cabdff1aSopenharmony_ci                                      NULL,                 // sampleSizeArray
676cabdff1aSopenharmony_ci                                      &sample_buf);
677cabdff1aSopenharmony_ci    }
678cabdff1aSopenharmony_ci
679cabdff1aSopenharmony_ci    if (block_buf)
680cabdff1aSopenharmony_ci        CFRelease(block_buf);
681cabdff1aSopenharmony_ci
682cabdff1aSopenharmony_ci    return sample_buf;
683cabdff1aSopenharmony_ci}
684cabdff1aSopenharmony_ci
685cabdff1aSopenharmony_cistatic void videotoolbox_decoder_callback(void *opaque,
686cabdff1aSopenharmony_ci                                          void *sourceFrameRefCon,
687cabdff1aSopenharmony_ci                                          OSStatus status,
688cabdff1aSopenharmony_ci                                          VTDecodeInfoFlags flags,
689cabdff1aSopenharmony_ci                                          CVImageBufferRef image_buffer,
690cabdff1aSopenharmony_ci                                          CMTime pts,
691cabdff1aSopenharmony_ci                                          CMTime duration)
692cabdff1aSopenharmony_ci{
693cabdff1aSopenharmony_ci    VTContext *vtctx = opaque;
694cabdff1aSopenharmony_ci
695cabdff1aSopenharmony_ci    if (vtctx->frame) {
696cabdff1aSopenharmony_ci        CVPixelBufferRelease(vtctx->frame);
697cabdff1aSopenharmony_ci        vtctx->frame = NULL;
698cabdff1aSopenharmony_ci    }
699cabdff1aSopenharmony_ci
700cabdff1aSopenharmony_ci    if (!image_buffer) {
701cabdff1aSopenharmony_ci        av_log(vtctx->logctx, status ? AV_LOG_WARNING : AV_LOG_DEBUG,
702cabdff1aSopenharmony_ci               "vt decoder cb: output image buffer is null: %i\n", status);
703cabdff1aSopenharmony_ci        return;
704cabdff1aSopenharmony_ci    }
705cabdff1aSopenharmony_ci
706cabdff1aSopenharmony_ci    vtctx->frame = CVPixelBufferRetain(image_buffer);
707cabdff1aSopenharmony_ci}
708cabdff1aSopenharmony_ci
709cabdff1aSopenharmony_cistatic OSStatus videotoolbox_session_decode_frame(AVCodecContext *avctx)
710cabdff1aSopenharmony_ci{
711cabdff1aSopenharmony_ci    OSStatus status;
712cabdff1aSopenharmony_ci    CMSampleBufferRef sample_buf;
713cabdff1aSopenharmony_ci    AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx);
714cabdff1aSopenharmony_ci    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
715cabdff1aSopenharmony_ci
716cabdff1aSopenharmony_ci    sample_buf = videotoolbox_sample_buffer_create(videotoolbox->cm_fmt_desc,
717cabdff1aSopenharmony_ci                                                   vtctx->bitstream,
718cabdff1aSopenharmony_ci                                                   vtctx->bitstream_size);
719cabdff1aSopenharmony_ci
720cabdff1aSopenharmony_ci    if (!sample_buf)
721cabdff1aSopenharmony_ci        return -1;
722cabdff1aSopenharmony_ci
723cabdff1aSopenharmony_ci    status = VTDecompressionSessionDecodeFrame(videotoolbox->session,
724cabdff1aSopenharmony_ci                                               sample_buf,
725cabdff1aSopenharmony_ci                                               0,       // decodeFlags
726cabdff1aSopenharmony_ci                                               NULL,    // sourceFrameRefCon
727cabdff1aSopenharmony_ci                                               0);      // infoFlagsOut
728cabdff1aSopenharmony_ci    if (status == noErr)
729cabdff1aSopenharmony_ci        status = VTDecompressionSessionWaitForAsynchronousFrames(videotoolbox->session);
730cabdff1aSopenharmony_ci
731cabdff1aSopenharmony_ci    CFRelease(sample_buf);
732cabdff1aSopenharmony_ci
733cabdff1aSopenharmony_ci    return status;
734cabdff1aSopenharmony_ci}
735cabdff1aSopenharmony_ci
736cabdff1aSopenharmony_cistatic CMVideoFormatDescriptionRef videotoolbox_format_desc_create(CMVideoCodecType codec_type,
737cabdff1aSopenharmony_ci                                                                   CFDictionaryRef decoder_spec,
738cabdff1aSopenharmony_ci                                                                   int width,
739cabdff1aSopenharmony_ci                                                                   int height)
740cabdff1aSopenharmony_ci{
741cabdff1aSopenharmony_ci    CMFormatDescriptionRef cm_fmt_desc;
742cabdff1aSopenharmony_ci    OSStatus status;
743cabdff1aSopenharmony_ci
744cabdff1aSopenharmony_ci    status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
745cabdff1aSopenharmony_ci                                            codec_type,
746cabdff1aSopenharmony_ci                                            width,
747cabdff1aSopenharmony_ci                                            height,
748cabdff1aSopenharmony_ci                                            decoder_spec, // Dictionary of extension
749cabdff1aSopenharmony_ci                                            &cm_fmt_desc);
750cabdff1aSopenharmony_ci
751cabdff1aSopenharmony_ci    if (status)
752cabdff1aSopenharmony_ci        return NULL;
753cabdff1aSopenharmony_ci
754cabdff1aSopenharmony_ci    return cm_fmt_desc;
755cabdff1aSopenharmony_ci}
756cabdff1aSopenharmony_ci
757cabdff1aSopenharmony_cistatic CFDictionaryRef videotoolbox_buffer_attributes_create(int width,
758cabdff1aSopenharmony_ci                                                             int height,
759cabdff1aSopenharmony_ci                                                             OSType pix_fmt)
760cabdff1aSopenharmony_ci{
761cabdff1aSopenharmony_ci    CFMutableDictionaryRef buffer_attributes;
762cabdff1aSopenharmony_ci    CFMutableDictionaryRef io_surface_properties;
763cabdff1aSopenharmony_ci    CFNumberRef cv_pix_fmt;
764cabdff1aSopenharmony_ci    CFNumberRef w;
765cabdff1aSopenharmony_ci    CFNumberRef h;
766cabdff1aSopenharmony_ci
767cabdff1aSopenharmony_ci    w = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &width);
768cabdff1aSopenharmony_ci    h = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &height);
769cabdff1aSopenharmony_ci    cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pix_fmt);
770cabdff1aSopenharmony_ci
771cabdff1aSopenharmony_ci    buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
772cabdff1aSopenharmony_ci                                                  4,
773cabdff1aSopenharmony_ci                                                  &kCFTypeDictionaryKeyCallBacks,
774cabdff1aSopenharmony_ci                                                  &kCFTypeDictionaryValueCallBacks);
775cabdff1aSopenharmony_ci    io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault,
776cabdff1aSopenharmony_ci                                                      0,
777cabdff1aSopenharmony_ci                                                      &kCFTypeDictionaryKeyCallBacks,
778cabdff1aSopenharmony_ci                                                      &kCFTypeDictionaryValueCallBacks);
779cabdff1aSopenharmony_ci
780cabdff1aSopenharmony_ci    if (pix_fmt)
781cabdff1aSopenharmony_ci        CFDictionarySetValue(buffer_attributes, kCVPixelBufferPixelFormatTypeKey, cv_pix_fmt);
782cabdff1aSopenharmony_ci    CFDictionarySetValue(buffer_attributes, kCVPixelBufferIOSurfacePropertiesKey, io_surface_properties);
783cabdff1aSopenharmony_ci    CFDictionarySetValue(buffer_attributes, kCVPixelBufferWidthKey, w);
784cabdff1aSopenharmony_ci    CFDictionarySetValue(buffer_attributes, kCVPixelBufferHeightKey, h);
785cabdff1aSopenharmony_ci#if TARGET_OS_IPHONE
786cabdff1aSopenharmony_ci    CFDictionarySetValue(buffer_attributes, kCVPixelBufferOpenGLESCompatibilityKey, kCFBooleanTrue);
787cabdff1aSopenharmony_ci#else
788cabdff1aSopenharmony_ci    CFDictionarySetValue(buffer_attributes, kCVPixelBufferIOSurfaceOpenGLTextureCompatibilityKey, kCFBooleanTrue);
789cabdff1aSopenharmony_ci#endif
790cabdff1aSopenharmony_ci
791cabdff1aSopenharmony_ci    CFRelease(io_surface_properties);
792cabdff1aSopenharmony_ci    CFRelease(cv_pix_fmt);
793cabdff1aSopenharmony_ci    CFRelease(w);
794cabdff1aSopenharmony_ci    CFRelease(h);
795cabdff1aSopenharmony_ci
796cabdff1aSopenharmony_ci    return buffer_attributes;
797cabdff1aSopenharmony_ci}
798cabdff1aSopenharmony_ci
799cabdff1aSopenharmony_cistatic CFDictionaryRef videotoolbox_decoder_config_create(CMVideoCodecType codec_type,
800cabdff1aSopenharmony_ci                                                          AVCodecContext *avctx)
801cabdff1aSopenharmony_ci{
802cabdff1aSopenharmony_ci    CFMutableDictionaryRef config_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
803cabdff1aSopenharmony_ci                                                                   0,
804cabdff1aSopenharmony_ci                                                                   &kCFTypeDictionaryKeyCallBacks,
805cabdff1aSopenharmony_ci                                                                   &kCFTypeDictionaryValueCallBacks);
806cabdff1aSopenharmony_ci
807cabdff1aSopenharmony_ci    CFDictionarySetValue(config_info,
808cabdff1aSopenharmony_ci                         codec_type == kCMVideoCodecType_HEVC ?
809cabdff1aSopenharmony_ci                            kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder :
810cabdff1aSopenharmony_ci                            kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder,
811cabdff1aSopenharmony_ci                         kCFBooleanTrue);
812cabdff1aSopenharmony_ci
813cabdff1aSopenharmony_ci    CFMutableDictionaryRef avc_info;
814cabdff1aSopenharmony_ci    CFDataRef data = NULL;
815cabdff1aSopenharmony_ci
816cabdff1aSopenharmony_ci    avc_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
817cabdff1aSopenharmony_ci                                         1,
818cabdff1aSopenharmony_ci                                         &kCFTypeDictionaryKeyCallBacks,
819cabdff1aSopenharmony_ci                                         &kCFTypeDictionaryValueCallBacks);
820cabdff1aSopenharmony_ci
821cabdff1aSopenharmony_ci    switch (codec_type) {
822cabdff1aSopenharmony_ci    case kCMVideoCodecType_MPEG4Video :
823cabdff1aSopenharmony_ci        if (avctx->extradata_size)
824cabdff1aSopenharmony_ci            data = videotoolbox_esds_extradata_create(avctx);
825cabdff1aSopenharmony_ci        if (data)
826cabdff1aSopenharmony_ci            CFDictionarySetValue(avc_info, CFSTR("esds"), data);
827cabdff1aSopenharmony_ci        break;
828cabdff1aSopenharmony_ci    case kCMVideoCodecType_H264 :
829cabdff1aSopenharmony_ci        data = ff_videotoolbox_avcc_extradata_create(avctx);
830cabdff1aSopenharmony_ci        if (data)
831cabdff1aSopenharmony_ci            CFDictionarySetValue(avc_info, CFSTR("avcC"), data);
832cabdff1aSopenharmony_ci        break;
833cabdff1aSopenharmony_ci    case kCMVideoCodecType_HEVC :
834cabdff1aSopenharmony_ci        data = ff_videotoolbox_hvcc_extradata_create(avctx);
835cabdff1aSopenharmony_ci        if (data)
836cabdff1aSopenharmony_ci            CFDictionarySetValue(avc_info, CFSTR("hvcC"), data);
837cabdff1aSopenharmony_ci        break;
838cabdff1aSopenharmony_ci#if CONFIG_VP9_VIDEOTOOLBOX_HWACCEL
839cabdff1aSopenharmony_ci    case kCMVideoCodecType_VP9 :
840cabdff1aSopenharmony_ci        data = ff_videotoolbox_vpcc_extradata_create(avctx);
841cabdff1aSopenharmony_ci        if (data)
842cabdff1aSopenharmony_ci            CFDictionarySetValue(avc_info, CFSTR("vpcC"), data);
843cabdff1aSopenharmony_ci        break;
844cabdff1aSopenharmony_ci#endif
845cabdff1aSopenharmony_ci    default:
846cabdff1aSopenharmony_ci        break;
847cabdff1aSopenharmony_ci    }
848cabdff1aSopenharmony_ci
849cabdff1aSopenharmony_ci    CFDictionarySetValue(config_info,
850cabdff1aSopenharmony_ci            kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms,
851cabdff1aSopenharmony_ci            avc_info);
852cabdff1aSopenharmony_ci
853cabdff1aSopenharmony_ci    if (data)
854cabdff1aSopenharmony_ci        CFRelease(data);
855cabdff1aSopenharmony_ci
856cabdff1aSopenharmony_ci    CFRelease(avc_info);
857cabdff1aSopenharmony_ci    return config_info;
858cabdff1aSopenharmony_ci}
859cabdff1aSopenharmony_ci
860cabdff1aSopenharmony_cistatic int videotoolbox_start(AVCodecContext *avctx)
861cabdff1aSopenharmony_ci{
862cabdff1aSopenharmony_ci    AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx);
863cabdff1aSopenharmony_ci    OSStatus status;
864cabdff1aSopenharmony_ci    VTDecompressionOutputCallbackRecord decoder_cb;
865cabdff1aSopenharmony_ci    CFDictionaryRef decoder_spec;
866cabdff1aSopenharmony_ci    CFDictionaryRef buf_attr;
867cabdff1aSopenharmony_ci
868cabdff1aSopenharmony_ci    if (!videotoolbox) {
869cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "hwaccel context is not set\n");
870cabdff1aSopenharmony_ci        return -1;
871cabdff1aSopenharmony_ci    }
872cabdff1aSopenharmony_ci
873cabdff1aSopenharmony_ci    switch( avctx->codec_id ) {
874cabdff1aSopenharmony_ci    case AV_CODEC_ID_H263 :
875cabdff1aSopenharmony_ci        videotoolbox->cm_codec_type = kCMVideoCodecType_H263;
876cabdff1aSopenharmony_ci        break;
877cabdff1aSopenharmony_ci    case AV_CODEC_ID_H264 :
878cabdff1aSopenharmony_ci        videotoolbox->cm_codec_type = kCMVideoCodecType_H264;
879cabdff1aSopenharmony_ci        break;
880cabdff1aSopenharmony_ci    case AV_CODEC_ID_HEVC :
881cabdff1aSopenharmony_ci        videotoolbox->cm_codec_type = kCMVideoCodecType_HEVC;
882cabdff1aSopenharmony_ci        break;
883cabdff1aSopenharmony_ci    case AV_CODEC_ID_MPEG1VIDEO :
884cabdff1aSopenharmony_ci        videotoolbox->cm_codec_type = kCMVideoCodecType_MPEG1Video;
885cabdff1aSopenharmony_ci        break;
886cabdff1aSopenharmony_ci    case AV_CODEC_ID_MPEG2VIDEO :
887cabdff1aSopenharmony_ci        videotoolbox->cm_codec_type = kCMVideoCodecType_MPEG2Video;
888cabdff1aSopenharmony_ci        break;
889cabdff1aSopenharmony_ci    case AV_CODEC_ID_MPEG4 :
890cabdff1aSopenharmony_ci        videotoolbox->cm_codec_type = kCMVideoCodecType_MPEG4Video;
891cabdff1aSopenharmony_ci        break;
892cabdff1aSopenharmony_ci    case AV_CODEC_ID_PRORES :
893cabdff1aSopenharmony_ci        switch (avctx->codec_tag) {
894cabdff1aSopenharmony_ci        default:
895cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_WARNING, "Unknown prores profile %d\n", avctx->codec_tag);
896cabdff1aSopenharmony_ci        // fall-through
897cabdff1aSopenharmony_ci        case MKTAG('a','p','c','o'): // kCMVideoCodecType_AppleProRes422Proxy
898cabdff1aSopenharmony_ci        case MKTAG('a','p','c','s'): // kCMVideoCodecType_AppleProRes422LT
899cabdff1aSopenharmony_ci        case MKTAG('a','p','c','n'): // kCMVideoCodecType_AppleProRes422
900cabdff1aSopenharmony_ci        case MKTAG('a','p','c','h'): // kCMVideoCodecType_AppleProRes422HQ
901cabdff1aSopenharmony_ci        case MKTAG('a','p','4','h'): // kCMVideoCodecType_AppleProRes4444
902cabdff1aSopenharmony_ci        case MKTAG('a','p','4','x'): // kCMVideoCodecType_AppleProRes4444XQ
903cabdff1aSopenharmony_ci            videotoolbox->cm_codec_type = av_bswap32(avctx->codec_tag);
904cabdff1aSopenharmony_ci            break;
905cabdff1aSopenharmony_ci        }
906cabdff1aSopenharmony_ci        break;
907cabdff1aSopenharmony_ci    case AV_CODEC_ID_VP9 :
908cabdff1aSopenharmony_ci        videotoolbox->cm_codec_type = kCMVideoCodecType_VP9;
909cabdff1aSopenharmony_ci        break;
910cabdff1aSopenharmony_ci    default :
911cabdff1aSopenharmony_ci        break;
912cabdff1aSopenharmony_ci    }
913cabdff1aSopenharmony_ci
914cabdff1aSopenharmony_ci#if defined(MAC_OS_X_VERSION_10_9) && !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9) && AV_HAS_BUILTIN(__builtin_available)
915cabdff1aSopenharmony_ci    if (avctx->codec_id == AV_CODEC_ID_PRORES) {
916cabdff1aSopenharmony_ci        if (__builtin_available(macOS 10.9, *)) {
917cabdff1aSopenharmony_ci            VTRegisterProfessionalVideoWorkflowVideoDecoders();
918cabdff1aSopenharmony_ci        }
919cabdff1aSopenharmony_ci    }
920cabdff1aSopenharmony_ci#endif
921cabdff1aSopenharmony_ci
922cabdff1aSopenharmony_ci#if defined(MAC_OS_VERSION_11_0) && !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0) && AV_HAS_BUILTIN(__builtin_available)
923cabdff1aSopenharmony_ci    if (__builtin_available(macOS 11.0, *)) {
924cabdff1aSopenharmony_ci        VTRegisterSupplementalVideoDecoderIfAvailable(videotoolbox->cm_codec_type);
925cabdff1aSopenharmony_ci    }
926cabdff1aSopenharmony_ci#endif
927cabdff1aSopenharmony_ci
928cabdff1aSopenharmony_ci    decoder_spec = videotoolbox_decoder_config_create(videotoolbox->cm_codec_type, avctx);
929cabdff1aSopenharmony_ci
930cabdff1aSopenharmony_ci    if (!decoder_spec) {
931cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "decoder specification creation failed\n");
932cabdff1aSopenharmony_ci        return -1;
933cabdff1aSopenharmony_ci    }
934cabdff1aSopenharmony_ci
935cabdff1aSopenharmony_ci    videotoolbox->cm_fmt_desc = videotoolbox_format_desc_create(videotoolbox->cm_codec_type,
936cabdff1aSopenharmony_ci                                                                decoder_spec,
937cabdff1aSopenharmony_ci                                                                avctx->width,
938cabdff1aSopenharmony_ci                                                                avctx->height);
939cabdff1aSopenharmony_ci    if (!videotoolbox->cm_fmt_desc) {
940cabdff1aSopenharmony_ci        if (decoder_spec)
941cabdff1aSopenharmony_ci            CFRelease(decoder_spec);
942cabdff1aSopenharmony_ci
943cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "format description creation failed\n");
944cabdff1aSopenharmony_ci        return -1;
945cabdff1aSopenharmony_ci    }
946cabdff1aSopenharmony_ci
947cabdff1aSopenharmony_ci    buf_attr = videotoolbox_buffer_attributes_create(avctx->width,
948cabdff1aSopenharmony_ci                                                     avctx->height,
949cabdff1aSopenharmony_ci                                                     videotoolbox->cv_pix_fmt_type);
950cabdff1aSopenharmony_ci
951cabdff1aSopenharmony_ci    decoder_cb.decompressionOutputCallback = videotoolbox_decoder_callback;
952cabdff1aSopenharmony_ci    decoder_cb.decompressionOutputRefCon   = avctx->internal->hwaccel_priv_data;
953cabdff1aSopenharmony_ci
954cabdff1aSopenharmony_ci    status = VTDecompressionSessionCreate(NULL,                      // allocator
955cabdff1aSopenharmony_ci                                          videotoolbox->cm_fmt_desc, // videoFormatDescription
956cabdff1aSopenharmony_ci                                          decoder_spec,              // videoDecoderSpecification
957cabdff1aSopenharmony_ci                                          buf_attr,                  // destinationImageBufferAttributes
958cabdff1aSopenharmony_ci                                          &decoder_cb,               // outputCallback
959cabdff1aSopenharmony_ci                                          &videotoolbox->session);   // decompressionSessionOut
960cabdff1aSopenharmony_ci
961cabdff1aSopenharmony_ci    if (decoder_spec)
962cabdff1aSopenharmony_ci        CFRelease(decoder_spec);
963cabdff1aSopenharmony_ci    if (buf_attr)
964cabdff1aSopenharmony_ci        CFRelease(buf_attr);
965cabdff1aSopenharmony_ci
966cabdff1aSopenharmony_ci    switch (status) {
967cabdff1aSopenharmony_ci    case kVTVideoDecoderNotAvailableNowErr:
968cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox session not available.\n");
969cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
970cabdff1aSopenharmony_ci    case kVTVideoDecoderUnsupportedDataFormatErr:
971cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox does not support this format.\n");
972cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
973cabdff1aSopenharmony_ci    case kVTCouldNotFindVideoDecoderErr:
974cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox decoder for this format not found.\n");
975cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
976cabdff1aSopenharmony_ci    case kVTVideoDecoderMalfunctionErr:
977cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox malfunction.\n");
978cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
979cabdff1aSopenharmony_ci    case kVTVideoDecoderBadDataErr:
980cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox reported invalid data.\n");
981cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
982cabdff1aSopenharmony_ci    case 0:
983cabdff1aSopenharmony_ci        return 0;
984cabdff1aSopenharmony_ci    default:
985cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_VERBOSE, "Unknown VideoToolbox session creation error %d\n", (int)status);
986cabdff1aSopenharmony_ci        return AVERROR_UNKNOWN;
987cabdff1aSopenharmony_ci    }
988cabdff1aSopenharmony_ci}
989cabdff1aSopenharmony_ci
990cabdff1aSopenharmony_cistatic const char *videotoolbox_error_string(OSStatus status)
991cabdff1aSopenharmony_ci{
992cabdff1aSopenharmony_ci    switch (status) {
993cabdff1aSopenharmony_ci        case kVTVideoDecoderBadDataErr:
994cabdff1aSopenharmony_ci            return "bad data";
995cabdff1aSopenharmony_ci        case kVTVideoDecoderMalfunctionErr:
996cabdff1aSopenharmony_ci            return "decoder malfunction";
997cabdff1aSopenharmony_ci        case kVTInvalidSessionErr:
998cabdff1aSopenharmony_ci            return "invalid session";
999cabdff1aSopenharmony_ci    }
1000cabdff1aSopenharmony_ci    return "unknown";
1001cabdff1aSopenharmony_ci}
1002cabdff1aSopenharmony_ci
1003cabdff1aSopenharmony_ciint ff_videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame)
1004cabdff1aSopenharmony_ci{
1005cabdff1aSopenharmony_ci    OSStatus status;
1006cabdff1aSopenharmony_ci    AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx);
1007cabdff1aSopenharmony_ci    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
1008cabdff1aSopenharmony_ci
1009cabdff1aSopenharmony_ci    if (vtctx->reconfig_needed == true) {
1010cabdff1aSopenharmony_ci        vtctx->reconfig_needed = false;
1011cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox decoder needs reconfig, restarting..\n");
1012cabdff1aSopenharmony_ci        videotoolbox_stop(avctx);
1013cabdff1aSopenharmony_ci        if (videotoolbox_start(avctx) != 0) {
1014cabdff1aSopenharmony_ci            return AVERROR_EXTERNAL;
1015cabdff1aSopenharmony_ci        }
1016cabdff1aSopenharmony_ci    }
1017cabdff1aSopenharmony_ci
1018cabdff1aSopenharmony_ci    if (!videotoolbox->session || !vtctx->bitstream || !vtctx->bitstream_size)
1019cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
1020cabdff1aSopenharmony_ci
1021cabdff1aSopenharmony_ci    status = videotoolbox_session_decode_frame(avctx);
1022cabdff1aSopenharmony_ci    if (status != noErr) {
1023cabdff1aSopenharmony_ci        if (status == kVTVideoDecoderMalfunctionErr || status == kVTInvalidSessionErr)
1024cabdff1aSopenharmony_ci            vtctx->reconfig_needed = true;
1025cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%s, %d)\n", videotoolbox_error_string(status), (int)status);
1026cabdff1aSopenharmony_ci        return AVERROR_UNKNOWN;
1027cabdff1aSopenharmony_ci    }
1028cabdff1aSopenharmony_ci
1029cabdff1aSopenharmony_ci    if (!vtctx->frame) {
1030cabdff1aSopenharmony_ci        vtctx->reconfig_needed = true;
1031cabdff1aSopenharmony_ci        return AVERROR_UNKNOWN;
1032cabdff1aSopenharmony_ci    }
1033cabdff1aSopenharmony_ci
1034cabdff1aSopenharmony_ci    return videotoolbox_buffer_create(avctx, frame);
1035cabdff1aSopenharmony_ci}
1036cabdff1aSopenharmony_ci
1037cabdff1aSopenharmony_cistatic int videotoolbox_h264_end_frame(AVCodecContext *avctx)
1038cabdff1aSopenharmony_ci{
1039cabdff1aSopenharmony_ci    H264Context *h = avctx->priv_data;
1040cabdff1aSopenharmony_ci    AVFrame *frame = h->cur_pic_ptr->f;
1041cabdff1aSopenharmony_ci    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
1042cabdff1aSopenharmony_ci    int ret = ff_videotoolbox_common_end_frame(avctx, frame);
1043cabdff1aSopenharmony_ci    vtctx->bitstream_size = 0;
1044cabdff1aSopenharmony_ci    return ret;
1045cabdff1aSopenharmony_ci}
1046cabdff1aSopenharmony_ci
1047cabdff1aSopenharmony_cistatic int videotoolbox_hevc_start_frame(AVCodecContext *avctx,
1048cabdff1aSopenharmony_ci                                         const uint8_t *buffer,
1049cabdff1aSopenharmony_ci                                         uint32_t size)
1050cabdff1aSopenharmony_ci{
1051cabdff1aSopenharmony_ci    return 0;
1052cabdff1aSopenharmony_ci}
1053cabdff1aSopenharmony_ci
1054cabdff1aSopenharmony_cistatic int videotoolbox_hevc_decode_slice(AVCodecContext *avctx,
1055cabdff1aSopenharmony_ci                                          const uint8_t *buffer,
1056cabdff1aSopenharmony_ci                                          uint32_t size)
1057cabdff1aSopenharmony_ci{
1058cabdff1aSopenharmony_ci    return videotoolbox_common_decode_slice(avctx, buffer, size);
1059cabdff1aSopenharmony_ci}
1060cabdff1aSopenharmony_ci
1061cabdff1aSopenharmony_ci
1062cabdff1aSopenharmony_cistatic int videotoolbox_hevc_decode_params(AVCodecContext *avctx,
1063cabdff1aSopenharmony_ci                                           int type,
1064cabdff1aSopenharmony_ci                                           const uint8_t *buffer,
1065cabdff1aSopenharmony_ci                                           uint32_t size)
1066cabdff1aSopenharmony_ci{
1067cabdff1aSopenharmony_ci    return videotoolbox_common_decode_slice(avctx, buffer, size);
1068cabdff1aSopenharmony_ci}
1069cabdff1aSopenharmony_ci
1070cabdff1aSopenharmony_cistatic int videotoolbox_hevc_end_frame(AVCodecContext *avctx)
1071cabdff1aSopenharmony_ci{
1072cabdff1aSopenharmony_ci    HEVCContext *h = avctx->priv_data;
1073cabdff1aSopenharmony_ci    AVFrame *frame = h->ref->frame;
1074cabdff1aSopenharmony_ci    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
1075cabdff1aSopenharmony_ci
1076cabdff1aSopenharmony_ci    h->output_frame->crop_right = 0;
1077cabdff1aSopenharmony_ci    h->output_frame->crop_left = 0;
1078cabdff1aSopenharmony_ci    h->output_frame->crop_top = 0;
1079cabdff1aSopenharmony_ci    h->output_frame->crop_bottom = 0;
1080cabdff1aSopenharmony_ci
1081cabdff1aSopenharmony_ci    int ret = ff_videotoolbox_common_end_frame(avctx, frame);
1082cabdff1aSopenharmony_ci    vtctx->bitstream_size = 0;
1083cabdff1aSopenharmony_ci    return ret;
1084cabdff1aSopenharmony_ci}
1085cabdff1aSopenharmony_ci
1086cabdff1aSopenharmony_cistatic int videotoolbox_mpeg_start_frame(AVCodecContext *avctx,
1087cabdff1aSopenharmony_ci                                         const uint8_t *buffer,
1088cabdff1aSopenharmony_ci                                         uint32_t size)
1089cabdff1aSopenharmony_ci{
1090cabdff1aSopenharmony_ci    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
1091cabdff1aSopenharmony_ci
1092cabdff1aSopenharmony_ci    return ff_videotoolbox_buffer_copy(vtctx, buffer, size);
1093cabdff1aSopenharmony_ci}
1094cabdff1aSopenharmony_ci
1095cabdff1aSopenharmony_cistatic int videotoolbox_mpeg_decode_slice(AVCodecContext *avctx,
1096cabdff1aSopenharmony_ci                                          const uint8_t *buffer,
1097cabdff1aSopenharmony_ci                                          uint32_t size)
1098cabdff1aSopenharmony_ci{
1099cabdff1aSopenharmony_ci    return 0;
1100cabdff1aSopenharmony_ci}
1101cabdff1aSopenharmony_ci
1102cabdff1aSopenharmony_cistatic int videotoolbox_mpeg_end_frame(AVCodecContext *avctx)
1103cabdff1aSopenharmony_ci{
1104cabdff1aSopenharmony_ci    MpegEncContext *s = avctx->priv_data;
1105cabdff1aSopenharmony_ci    AVFrame *frame = s->current_picture_ptr->f;
1106cabdff1aSopenharmony_ci
1107cabdff1aSopenharmony_ci    return ff_videotoolbox_common_end_frame(avctx, frame);
1108cabdff1aSopenharmony_ci}
1109cabdff1aSopenharmony_ci
1110cabdff1aSopenharmony_cistatic int videotoolbox_prores_start_frame(AVCodecContext *avctx,
1111cabdff1aSopenharmony_ci                                         const uint8_t *buffer,
1112cabdff1aSopenharmony_ci                                         uint32_t size)
1113cabdff1aSopenharmony_ci{
1114cabdff1aSopenharmony_ci    return 0;
1115cabdff1aSopenharmony_ci}
1116cabdff1aSopenharmony_ci
1117cabdff1aSopenharmony_cistatic int videotoolbox_prores_decode_slice(AVCodecContext *avctx,
1118cabdff1aSopenharmony_ci                                          const uint8_t *buffer,
1119cabdff1aSopenharmony_ci                                          uint32_t size)
1120cabdff1aSopenharmony_ci{
1121cabdff1aSopenharmony_ci    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
1122cabdff1aSopenharmony_ci
1123cabdff1aSopenharmony_ci    return ff_videotoolbox_buffer_copy(vtctx, buffer, size);
1124cabdff1aSopenharmony_ci}
1125cabdff1aSopenharmony_ci
1126cabdff1aSopenharmony_cistatic int videotoolbox_prores_end_frame(AVCodecContext *avctx)
1127cabdff1aSopenharmony_ci{
1128cabdff1aSopenharmony_ci    ProresContext *ctx = avctx->priv_data;
1129cabdff1aSopenharmony_ci    AVFrame *frame = ctx->frame;
1130cabdff1aSopenharmony_ci
1131cabdff1aSopenharmony_ci    return ff_videotoolbox_common_end_frame(avctx, frame);
1132cabdff1aSopenharmony_ci}
1133cabdff1aSopenharmony_ci
1134cabdff1aSopenharmony_cistatic enum AVPixelFormat videotoolbox_best_pixel_format(AVCodecContext *avctx) {
1135cabdff1aSopenharmony_ci    const AVPixFmtDescriptor *descriptor = av_pix_fmt_desc_get(avctx->sw_pix_fmt);
1136cabdff1aSopenharmony_ci    if (!descriptor)
1137cabdff1aSopenharmony_ci        return AV_PIX_FMT_NV12; // same as av_videotoolbox_alloc_context()
1138cabdff1aSopenharmony_ci
1139cabdff1aSopenharmony_ci    int depth = descriptor->comp[0].depth;
1140cabdff1aSopenharmony_ci
1141cabdff1aSopenharmony_ci    if (descriptor->flags & AV_PIX_FMT_FLAG_ALPHA)
1142cabdff1aSopenharmony_ci        return AV_PIX_FMT_AYUV64;
1143cabdff1aSopenharmony_ci
1144cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE
1145cabdff1aSopenharmony_ci    if (depth > 10)
1146cabdff1aSopenharmony_ci        return descriptor->log2_chroma_w == 0 ? AV_PIX_FMT_P416 : AV_PIX_FMT_P216;
1147cabdff1aSopenharmony_ci#endif
1148cabdff1aSopenharmony_ci
1149cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_444YPCBCR10BIPLANARVIDEORANGE
1150cabdff1aSopenharmony_ci    if (descriptor->log2_chroma_w == 0) {
1151cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_444YPCBCR8BIPLANARVIDEORANGE
1152cabdff1aSopenharmony_ci        if (depth <= 8)
1153cabdff1aSopenharmony_ci            return AV_PIX_FMT_NV24;
1154cabdff1aSopenharmony_ci#endif
1155cabdff1aSopenharmony_ci        return AV_PIX_FMT_P410;
1156cabdff1aSopenharmony_ci    }
1157cabdff1aSopenharmony_ci#endif
1158cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_422YPCBCR10BIPLANARVIDEORANGE
1159cabdff1aSopenharmony_ci    if (descriptor->log2_chroma_h == 0) {
1160cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_422YPCBCR8BIPLANARVIDEORANGE
1161cabdff1aSopenharmony_ci        if (depth <= 8)
1162cabdff1aSopenharmony_ci            return AV_PIX_FMT_NV16;
1163cabdff1aSopenharmony_ci#endif
1164cabdff1aSopenharmony_ci        return AV_PIX_FMT_P210;
1165cabdff1aSopenharmony_ci    }
1166cabdff1aSopenharmony_ci#endif
1167cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
1168cabdff1aSopenharmony_ci    if (depth > 8) {
1169cabdff1aSopenharmony_ci        return AV_PIX_FMT_P010;
1170cabdff1aSopenharmony_ci    }
1171cabdff1aSopenharmony_ci#endif
1172cabdff1aSopenharmony_ci
1173cabdff1aSopenharmony_ci    return AV_PIX_FMT_NV12;
1174cabdff1aSopenharmony_ci}
1175cabdff1aSopenharmony_ci
1176cabdff1aSopenharmony_ciint ff_videotoolbox_common_init(AVCodecContext *avctx)
1177cabdff1aSopenharmony_ci{
1178cabdff1aSopenharmony_ci    VTContext *vtctx = avctx->internal->hwaccel_priv_data;
1179cabdff1aSopenharmony_ci    AVHWFramesContext *hw_frames;
1180cabdff1aSopenharmony_ci    int err;
1181cabdff1aSopenharmony_ci
1182cabdff1aSopenharmony_ci    vtctx->logctx = avctx;
1183cabdff1aSopenharmony_ci
1184cabdff1aSopenharmony_ci    // Old API - do nothing.
1185cabdff1aSopenharmony_ci    if (avctx->hwaccel_context)
1186cabdff1aSopenharmony_ci        return 0;
1187cabdff1aSopenharmony_ci
1188cabdff1aSopenharmony_ci    if (!avctx->hw_frames_ctx && !avctx->hw_device_ctx) {
1189cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
1190cabdff1aSopenharmony_ci               "Either hw_frames_ctx or hw_device_ctx must be set.\n");
1191cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
1192cabdff1aSopenharmony_ci    }
1193cabdff1aSopenharmony_ci
1194cabdff1aSopenharmony_ci    vtctx->vt_ctx = av_videotoolbox_alloc_context();
1195cabdff1aSopenharmony_ci    if (!vtctx->vt_ctx) {
1196cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
1197cabdff1aSopenharmony_ci        goto fail;
1198cabdff1aSopenharmony_ci    }
1199cabdff1aSopenharmony_ci
1200cabdff1aSopenharmony_ci    if (avctx->hw_frames_ctx) {
1201cabdff1aSopenharmony_ci        hw_frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
1202cabdff1aSopenharmony_ci    } else {
1203cabdff1aSopenharmony_ci        avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx);
1204cabdff1aSopenharmony_ci        if (!avctx->hw_frames_ctx) {
1205cabdff1aSopenharmony_ci            err = AVERROR(ENOMEM);
1206cabdff1aSopenharmony_ci            goto fail;
1207cabdff1aSopenharmony_ci        }
1208cabdff1aSopenharmony_ci
1209cabdff1aSopenharmony_ci        hw_frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
1210cabdff1aSopenharmony_ci        hw_frames->format = AV_PIX_FMT_VIDEOTOOLBOX;
1211cabdff1aSopenharmony_ci        hw_frames->sw_format = videotoolbox_best_pixel_format(avctx);
1212cabdff1aSopenharmony_ci        hw_frames->width = avctx->width;
1213cabdff1aSopenharmony_ci        hw_frames->height = avctx->height;
1214cabdff1aSopenharmony_ci
1215cabdff1aSopenharmony_ci        err = av_hwframe_ctx_init(avctx->hw_frames_ctx);
1216cabdff1aSopenharmony_ci        if (err < 0) {
1217cabdff1aSopenharmony_ci            av_buffer_unref(&avctx->hw_frames_ctx);
1218cabdff1aSopenharmony_ci            goto fail;
1219cabdff1aSopenharmony_ci        }
1220cabdff1aSopenharmony_ci    }
1221cabdff1aSopenharmony_ci
1222cabdff1aSopenharmony_ci    vtctx->cached_hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx);
1223cabdff1aSopenharmony_ci    if (!vtctx->cached_hw_frames_ctx) {
1224cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
1225cabdff1aSopenharmony_ci        goto fail;
1226cabdff1aSopenharmony_ci    }
1227cabdff1aSopenharmony_ci
1228cabdff1aSopenharmony_ci    bool full_range = avctx->color_range == AVCOL_RANGE_JPEG;
1229cabdff1aSopenharmony_ci    vtctx->vt_ctx->cv_pix_fmt_type =
1230cabdff1aSopenharmony_ci        av_map_videotoolbox_format_from_pixfmt2(hw_frames->sw_format, full_range);
1231cabdff1aSopenharmony_ci    if (!vtctx->vt_ctx->cv_pix_fmt_type) {
1232cabdff1aSopenharmony_ci        const AVPixFmtDescriptor *attempted_format =
1233cabdff1aSopenharmony_ci            av_pix_fmt_desc_get(hw_frames->sw_format);
1234cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
1235cabdff1aSopenharmony_ci               "Failed to map underlying FFmpeg pixel format %s (%s range) to "
1236cabdff1aSopenharmony_ci               "a VideoToolbox format!\n",
1237cabdff1aSopenharmony_ci               attempted_format ? attempted_format->name : "<unknown>",
1238cabdff1aSopenharmony_ci               av_color_range_name(avctx->color_range));
1239cabdff1aSopenharmony_ci        err = AVERROR(EINVAL);
1240cabdff1aSopenharmony_ci        goto fail;
1241cabdff1aSopenharmony_ci    }
1242cabdff1aSopenharmony_ci
1243cabdff1aSopenharmony_ci    err = videotoolbox_start(avctx);
1244cabdff1aSopenharmony_ci    if (err < 0)
1245cabdff1aSopenharmony_ci        goto fail;
1246cabdff1aSopenharmony_ci
1247cabdff1aSopenharmony_ci    return 0;
1248cabdff1aSopenharmony_ci
1249cabdff1aSopenharmony_cifail:
1250cabdff1aSopenharmony_ci    ff_videotoolbox_uninit(avctx);
1251cabdff1aSopenharmony_ci    return err;
1252cabdff1aSopenharmony_ci}
1253cabdff1aSopenharmony_ci
1254cabdff1aSopenharmony_ciint ff_videotoolbox_frame_params(AVCodecContext *avctx,
1255cabdff1aSopenharmony_ci                                 AVBufferRef *hw_frames_ctx)
1256cabdff1aSopenharmony_ci{
1257cabdff1aSopenharmony_ci    AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data;
1258cabdff1aSopenharmony_ci
1259cabdff1aSopenharmony_ci    frames_ctx->format            = AV_PIX_FMT_VIDEOTOOLBOX;
1260cabdff1aSopenharmony_ci    frames_ctx->width             = avctx->coded_width;
1261cabdff1aSopenharmony_ci    frames_ctx->height            = avctx->coded_height;
1262cabdff1aSopenharmony_ci    frames_ctx->sw_format         = videotoolbox_best_pixel_format(avctx);
1263cabdff1aSopenharmony_ci
1264cabdff1aSopenharmony_ci    return 0;
1265cabdff1aSopenharmony_ci}
1266cabdff1aSopenharmony_ci
1267cabdff1aSopenharmony_ciconst AVHWAccel ff_h263_videotoolbox_hwaccel = {
1268cabdff1aSopenharmony_ci    .name           = "h263_videotoolbox",
1269cabdff1aSopenharmony_ci    .type           = AVMEDIA_TYPE_VIDEO,
1270cabdff1aSopenharmony_ci    .id             = AV_CODEC_ID_H263,
1271cabdff1aSopenharmony_ci    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
1272cabdff1aSopenharmony_ci    .alloc_frame    = ff_videotoolbox_alloc_frame,
1273cabdff1aSopenharmony_ci    .start_frame    = videotoolbox_mpeg_start_frame,
1274cabdff1aSopenharmony_ci    .decode_slice   = videotoolbox_mpeg_decode_slice,
1275cabdff1aSopenharmony_ci    .end_frame      = videotoolbox_mpeg_end_frame,
1276cabdff1aSopenharmony_ci    .frame_params   = ff_videotoolbox_frame_params,
1277cabdff1aSopenharmony_ci    .init           = ff_videotoolbox_common_init,
1278cabdff1aSopenharmony_ci    .uninit         = ff_videotoolbox_uninit,
1279cabdff1aSopenharmony_ci    .priv_data_size = sizeof(VTContext),
1280cabdff1aSopenharmony_ci};
1281cabdff1aSopenharmony_ci
1282cabdff1aSopenharmony_ciconst AVHWAccel ff_hevc_videotoolbox_hwaccel = {
1283cabdff1aSopenharmony_ci    .name           = "hevc_videotoolbox",
1284cabdff1aSopenharmony_ci    .type           = AVMEDIA_TYPE_VIDEO,
1285cabdff1aSopenharmony_ci    .id             = AV_CODEC_ID_HEVC,
1286cabdff1aSopenharmony_ci    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
1287cabdff1aSopenharmony_ci    .alloc_frame    = ff_videotoolbox_alloc_frame,
1288cabdff1aSopenharmony_ci    .start_frame    = videotoolbox_hevc_start_frame,
1289cabdff1aSopenharmony_ci    .decode_slice   = videotoolbox_hevc_decode_slice,
1290cabdff1aSopenharmony_ci    .decode_params  = videotoolbox_hevc_decode_params,
1291cabdff1aSopenharmony_ci    .end_frame      = videotoolbox_hevc_end_frame,
1292cabdff1aSopenharmony_ci    .frame_params   = ff_videotoolbox_frame_params,
1293cabdff1aSopenharmony_ci    .init           = ff_videotoolbox_common_init,
1294cabdff1aSopenharmony_ci    .uninit         = ff_videotoolbox_uninit,
1295cabdff1aSopenharmony_ci    .priv_data_size = sizeof(VTContext),
1296cabdff1aSopenharmony_ci};
1297cabdff1aSopenharmony_ci
1298cabdff1aSopenharmony_ciconst AVHWAccel ff_h264_videotoolbox_hwaccel = {
1299cabdff1aSopenharmony_ci    .name           = "h264_videotoolbox",
1300cabdff1aSopenharmony_ci    .type           = AVMEDIA_TYPE_VIDEO,
1301cabdff1aSopenharmony_ci    .id             = AV_CODEC_ID_H264,
1302cabdff1aSopenharmony_ci    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
1303cabdff1aSopenharmony_ci    .alloc_frame    = ff_videotoolbox_alloc_frame,
1304cabdff1aSopenharmony_ci    .start_frame    = ff_videotoolbox_h264_start_frame,
1305cabdff1aSopenharmony_ci    .decode_slice   = ff_videotoolbox_h264_decode_slice,
1306cabdff1aSopenharmony_ci    .decode_params  = videotoolbox_h264_decode_params,
1307cabdff1aSopenharmony_ci    .end_frame      = videotoolbox_h264_end_frame,
1308cabdff1aSopenharmony_ci    .frame_params   = ff_videotoolbox_frame_params,
1309cabdff1aSopenharmony_ci    .init           = ff_videotoolbox_common_init,
1310cabdff1aSopenharmony_ci    .uninit         = ff_videotoolbox_uninit,
1311cabdff1aSopenharmony_ci    .priv_data_size = sizeof(VTContext),
1312cabdff1aSopenharmony_ci};
1313cabdff1aSopenharmony_ci
1314cabdff1aSopenharmony_ciconst AVHWAccel ff_mpeg1_videotoolbox_hwaccel = {
1315cabdff1aSopenharmony_ci    .name           = "mpeg1_videotoolbox",
1316cabdff1aSopenharmony_ci    .type           = AVMEDIA_TYPE_VIDEO,
1317cabdff1aSopenharmony_ci    .id             = AV_CODEC_ID_MPEG1VIDEO,
1318cabdff1aSopenharmony_ci    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
1319cabdff1aSopenharmony_ci    .alloc_frame    = ff_videotoolbox_alloc_frame,
1320cabdff1aSopenharmony_ci    .start_frame    = videotoolbox_mpeg_start_frame,
1321cabdff1aSopenharmony_ci    .decode_slice   = videotoolbox_mpeg_decode_slice,
1322cabdff1aSopenharmony_ci    .end_frame      = videotoolbox_mpeg_end_frame,
1323cabdff1aSopenharmony_ci    .frame_params   = ff_videotoolbox_frame_params,
1324cabdff1aSopenharmony_ci    .init           = ff_videotoolbox_common_init,
1325cabdff1aSopenharmony_ci    .uninit         = ff_videotoolbox_uninit,
1326cabdff1aSopenharmony_ci    .priv_data_size = sizeof(VTContext),
1327cabdff1aSopenharmony_ci};
1328cabdff1aSopenharmony_ci
1329cabdff1aSopenharmony_ciconst AVHWAccel ff_mpeg2_videotoolbox_hwaccel = {
1330cabdff1aSopenharmony_ci    .name           = "mpeg2_videotoolbox",
1331cabdff1aSopenharmony_ci    .type           = AVMEDIA_TYPE_VIDEO,
1332cabdff1aSopenharmony_ci    .id             = AV_CODEC_ID_MPEG2VIDEO,
1333cabdff1aSopenharmony_ci    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
1334cabdff1aSopenharmony_ci    .alloc_frame    = ff_videotoolbox_alloc_frame,
1335cabdff1aSopenharmony_ci    .start_frame    = videotoolbox_mpeg_start_frame,
1336cabdff1aSopenharmony_ci    .decode_slice   = videotoolbox_mpeg_decode_slice,
1337cabdff1aSopenharmony_ci    .end_frame      = videotoolbox_mpeg_end_frame,
1338cabdff1aSopenharmony_ci    .frame_params   = ff_videotoolbox_frame_params,
1339cabdff1aSopenharmony_ci    .init           = ff_videotoolbox_common_init,
1340cabdff1aSopenharmony_ci    .uninit         = ff_videotoolbox_uninit,
1341cabdff1aSopenharmony_ci    .priv_data_size = sizeof(VTContext),
1342cabdff1aSopenharmony_ci};
1343cabdff1aSopenharmony_ci
1344cabdff1aSopenharmony_ciconst AVHWAccel ff_mpeg4_videotoolbox_hwaccel = {
1345cabdff1aSopenharmony_ci    .name           = "mpeg4_videotoolbox",
1346cabdff1aSopenharmony_ci    .type           = AVMEDIA_TYPE_VIDEO,
1347cabdff1aSopenharmony_ci    .id             = AV_CODEC_ID_MPEG4,
1348cabdff1aSopenharmony_ci    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
1349cabdff1aSopenharmony_ci    .alloc_frame    = ff_videotoolbox_alloc_frame,
1350cabdff1aSopenharmony_ci    .start_frame    = videotoolbox_mpeg_start_frame,
1351cabdff1aSopenharmony_ci    .decode_slice   = videotoolbox_mpeg_decode_slice,
1352cabdff1aSopenharmony_ci    .end_frame      = videotoolbox_mpeg_end_frame,
1353cabdff1aSopenharmony_ci    .frame_params   = ff_videotoolbox_frame_params,
1354cabdff1aSopenharmony_ci    .init           = ff_videotoolbox_common_init,
1355cabdff1aSopenharmony_ci    .uninit         = ff_videotoolbox_uninit,
1356cabdff1aSopenharmony_ci    .priv_data_size = sizeof(VTContext),
1357cabdff1aSopenharmony_ci};
1358cabdff1aSopenharmony_ci
1359cabdff1aSopenharmony_ciconst AVHWAccel ff_prores_videotoolbox_hwaccel = {
1360cabdff1aSopenharmony_ci    .name           = "prores_videotoolbox",
1361cabdff1aSopenharmony_ci    .type           = AVMEDIA_TYPE_VIDEO,
1362cabdff1aSopenharmony_ci    .id             = AV_CODEC_ID_PRORES,
1363cabdff1aSopenharmony_ci    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
1364cabdff1aSopenharmony_ci    .alloc_frame    = ff_videotoolbox_alloc_frame,
1365cabdff1aSopenharmony_ci    .start_frame    = videotoolbox_prores_start_frame,
1366cabdff1aSopenharmony_ci    .decode_slice   = videotoolbox_prores_decode_slice,
1367cabdff1aSopenharmony_ci    .end_frame      = videotoolbox_prores_end_frame,
1368cabdff1aSopenharmony_ci    .frame_params   = ff_videotoolbox_frame_params,
1369cabdff1aSopenharmony_ci    .init           = ff_videotoolbox_common_init,
1370cabdff1aSopenharmony_ci    .uninit         = ff_videotoolbox_uninit,
1371cabdff1aSopenharmony_ci    .priv_data_size = sizeof(VTContext),
1372cabdff1aSopenharmony_ci};
1373cabdff1aSopenharmony_ci
1374cabdff1aSopenharmony_cistatic AVVideotoolboxContext *av_videotoolbox_alloc_context_with_pix_fmt(enum AVPixelFormat pix_fmt,
1375cabdff1aSopenharmony_ci                                                                         bool full_range)
1376cabdff1aSopenharmony_ci{
1377cabdff1aSopenharmony_ci    AVVideotoolboxContext *ret = av_mallocz(sizeof(*ret));
1378cabdff1aSopenharmony_ci
1379cabdff1aSopenharmony_ci    if (ret) {
1380cabdff1aSopenharmony_ci        ret->output_callback = videotoolbox_decoder_callback;
1381cabdff1aSopenharmony_ci
1382cabdff1aSopenharmony_ci        OSType cv_pix_fmt_type = av_map_videotoolbox_format_from_pixfmt2(pix_fmt, full_range);
1383cabdff1aSopenharmony_ci        if (cv_pix_fmt_type == 0) {
1384cabdff1aSopenharmony_ci            cv_pix_fmt_type = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
1385cabdff1aSopenharmony_ci        }
1386cabdff1aSopenharmony_ci        ret->cv_pix_fmt_type = cv_pix_fmt_type;
1387cabdff1aSopenharmony_ci    }
1388cabdff1aSopenharmony_ci
1389cabdff1aSopenharmony_ci    return ret;
1390cabdff1aSopenharmony_ci}
1391cabdff1aSopenharmony_ci
1392cabdff1aSopenharmony_ciAVVideotoolboxContext *av_videotoolbox_alloc_context(void)
1393cabdff1aSopenharmony_ci{
1394cabdff1aSopenharmony_ci    return av_videotoolbox_alloc_context_with_pix_fmt(AV_PIX_FMT_NONE, false);
1395cabdff1aSopenharmony_ci}
1396cabdff1aSopenharmony_ci
1397cabdff1aSopenharmony_ciint av_videotoolbox_default_init(AVCodecContext *avctx)
1398cabdff1aSopenharmony_ci{
1399cabdff1aSopenharmony_ci    return av_videotoolbox_default_init2(avctx, NULL);
1400cabdff1aSopenharmony_ci}
1401cabdff1aSopenharmony_ci
1402cabdff1aSopenharmony_ciint av_videotoolbox_default_init2(AVCodecContext *avctx, AVVideotoolboxContext *vtctx)
1403cabdff1aSopenharmony_ci{
1404cabdff1aSopenharmony_ci    enum AVPixelFormat pix_fmt = videotoolbox_best_pixel_format(avctx);
1405cabdff1aSopenharmony_ci    bool full_range = avctx->color_range == AVCOL_RANGE_JPEG;
1406cabdff1aSopenharmony_ci    avctx->hwaccel_context = vtctx ?: av_videotoolbox_alloc_context_with_pix_fmt(pix_fmt, full_range);
1407cabdff1aSopenharmony_ci    if (!avctx->hwaccel_context)
1408cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
1409cabdff1aSopenharmony_ci    return videotoolbox_start(avctx);
1410cabdff1aSopenharmony_ci}
1411cabdff1aSopenharmony_ci
1412cabdff1aSopenharmony_civoid av_videotoolbox_default_free(AVCodecContext *avctx)
1413cabdff1aSopenharmony_ci{
1414cabdff1aSopenharmony_ci
1415cabdff1aSopenharmony_ci    videotoolbox_stop(avctx);
1416cabdff1aSopenharmony_ci    av_freep(&avctx->hwaccel_context);
1417cabdff1aSopenharmony_ci}
1418cabdff1aSopenharmony_ci#endif /* CONFIG_VIDEOTOOLBOX */
1419