1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * This file is part of FFmpeg.
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
8cabdff1aSopenharmony_ci *
9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12cabdff1aSopenharmony_ci * Lesser General Public License for more details.
13cabdff1aSopenharmony_ci *
14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17cabdff1aSopenharmony_ci */
18cabdff1aSopenharmony_ci
19cabdff1aSopenharmony_ci#include "config.h"
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci#include <stdint.h>
22cabdff1aSopenharmony_ci#include <string.h>
23cabdff1aSopenharmony_ci
24cabdff1aSopenharmony_ci#include <VideoToolbox/VideoToolbox.h>
25cabdff1aSopenharmony_ci
26cabdff1aSopenharmony_ci#include "buffer.h"
27cabdff1aSopenharmony_ci#include "buffer_internal.h"
28cabdff1aSopenharmony_ci#include "common.h"
29cabdff1aSopenharmony_ci#include "hwcontext.h"
30cabdff1aSopenharmony_ci#include "hwcontext_internal.h"
31cabdff1aSopenharmony_ci#include "hwcontext_videotoolbox.h"
32cabdff1aSopenharmony_ci#include "mem.h"
33cabdff1aSopenharmony_ci#include "pixfmt.h"
34cabdff1aSopenharmony_ci#include "pixdesc.h"
35cabdff1aSopenharmony_ci
36cabdff1aSopenharmony_citypedef struct VTFramesContext {
37cabdff1aSopenharmony_ci    CVPixelBufferPoolRef pool;
38cabdff1aSopenharmony_ci} VTFramesContext;
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_cistatic const struct {
41cabdff1aSopenharmony_ci    uint32_t cv_fmt;
42cabdff1aSopenharmony_ci    bool full_range;
43cabdff1aSopenharmony_ci    enum AVPixelFormat pix_fmt;
44cabdff1aSopenharmony_ci} cv_pix_fmts[] = {
45cabdff1aSopenharmony_ci    { kCVPixelFormatType_420YpCbCr8Planar,              false, AV_PIX_FMT_YUV420P },
46cabdff1aSopenharmony_ci    { kCVPixelFormatType_422YpCbCr8,                    false, AV_PIX_FMT_UYVY422 },
47cabdff1aSopenharmony_ci    { kCVPixelFormatType_32BGRA,                        false, AV_PIX_FMT_BGRA },
48cabdff1aSopenharmony_ci#ifdef kCFCoreFoundationVersionNumber10_7
49cabdff1aSopenharmony_ci    { kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,  false, AV_PIX_FMT_NV12 },
50cabdff1aSopenharmony_ci    { kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,   true,  AV_PIX_FMT_NV12 },
51cabdff1aSopenharmony_ci    { kCVPixelFormatType_4444AYpCbCr16,                 false, AV_PIX_FMT_AYUV64 },
52cabdff1aSopenharmony_ci#endif
53cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
54cabdff1aSopenharmony_ci    { kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange, false, AV_PIX_FMT_P010 },
55cabdff1aSopenharmony_ci    { kCVPixelFormatType_420YpCbCr10BiPlanarFullRange,  true,  AV_PIX_FMT_P010 },
56cabdff1aSopenharmony_ci#endif
57cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_422YPCBCR8BIPLANARVIDEORANGE
58cabdff1aSopenharmony_ci    { kCVPixelFormatType_422YpCbCr8BiPlanarVideoRange,  false, AV_PIX_FMT_NV16 },
59cabdff1aSopenharmony_ci    { kCVPixelFormatType_422YpCbCr8BiPlanarFullRange,   true,  AV_PIX_FMT_NV16 },
60cabdff1aSopenharmony_ci#endif
61cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_422YPCBCR10BIPLANARVIDEORANGE
62cabdff1aSopenharmony_ci    { kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange, false, AV_PIX_FMT_P210 },
63cabdff1aSopenharmony_ci    { kCVPixelFormatType_422YpCbCr10BiPlanarFullRange,  true,  AV_PIX_FMT_P210 },
64cabdff1aSopenharmony_ci#endif
65cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_422YPCBCR16BIPLANARVIDEORANGE
66cabdff1aSopenharmony_ci    { kCVPixelFormatType_422YpCbCr16BiPlanarVideoRange, false, AV_PIX_FMT_P216 },
67cabdff1aSopenharmony_ci#endif
68cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_444YPCBCR8BIPLANARVIDEORANGE
69cabdff1aSopenharmony_ci    { kCVPixelFormatType_444YpCbCr8BiPlanarVideoRange,  false, AV_PIX_FMT_NV24 },
70cabdff1aSopenharmony_ci    { kCVPixelFormatType_444YpCbCr8BiPlanarFullRange,   true,  AV_PIX_FMT_NV24 },
71cabdff1aSopenharmony_ci#endif
72cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_444YPCBCR10BIPLANARVIDEORANGE
73cabdff1aSopenharmony_ci    { kCVPixelFormatType_444YpCbCr10BiPlanarVideoRange, false, AV_PIX_FMT_P410 },
74cabdff1aSopenharmony_ci    { kCVPixelFormatType_444YpCbCr10BiPlanarFullRange,  true,  AV_PIX_FMT_P410 },
75cabdff1aSopenharmony_ci#endif
76cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE
77cabdff1aSopenharmony_ci    { kCVPixelFormatType_444YpCbCr16BiPlanarVideoRange, false, AV_PIX_FMT_P416 },
78cabdff1aSopenharmony_ci#endif
79cabdff1aSopenharmony_ci};
80cabdff1aSopenharmony_ci
81cabdff1aSopenharmony_cistatic const enum AVPixelFormat supported_formats[] = {
82cabdff1aSopenharmony_ci#ifdef kCFCoreFoundationVersionNumber10_7
83cabdff1aSopenharmony_ci    AV_PIX_FMT_NV12,
84cabdff1aSopenharmony_ci    AV_PIX_FMT_AYUV64,
85cabdff1aSopenharmony_ci#endif
86cabdff1aSopenharmony_ci    AV_PIX_FMT_YUV420P,
87cabdff1aSopenharmony_ci    AV_PIX_FMT_UYVY422,
88cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
89cabdff1aSopenharmony_ci    AV_PIX_FMT_P010,
90cabdff1aSopenharmony_ci#endif
91cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_422YPCBCR8BIPLANARVIDEORANGE
92cabdff1aSopenharmony_ci    AV_PIX_FMT_NV16,
93cabdff1aSopenharmony_ci#endif
94cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_422YPCBCR10BIPLANARVIDEORANGE
95cabdff1aSopenharmony_ci    AV_PIX_FMT_P210,
96cabdff1aSopenharmony_ci#endif
97cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_422YPCBCR16BIPLANARVIDEORANGE
98cabdff1aSopenharmony_ci    AV_PIX_FMT_P216,
99cabdff1aSopenharmony_ci#endif
100cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_444YPCBCR8BIPLANARVIDEORANGE
101cabdff1aSopenharmony_ci    AV_PIX_FMT_NV24,
102cabdff1aSopenharmony_ci#endif
103cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_444YPCBCR10BIPLANARVIDEORANGE
104cabdff1aSopenharmony_ci    AV_PIX_FMT_P410,
105cabdff1aSopenharmony_ci#endif
106cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE
107cabdff1aSopenharmony_ci    AV_PIX_FMT_P416,
108cabdff1aSopenharmony_ci#endif
109cabdff1aSopenharmony_ci    AV_PIX_FMT_BGRA,
110cabdff1aSopenharmony_ci};
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_cistatic int vt_frames_get_constraints(AVHWDeviceContext *ctx,
113cabdff1aSopenharmony_ci                                     const void *hwconfig,
114cabdff1aSopenharmony_ci                                     AVHWFramesConstraints *constraints)
115cabdff1aSopenharmony_ci{
116cabdff1aSopenharmony_ci    int i;
117cabdff1aSopenharmony_ci
118cabdff1aSopenharmony_ci    constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(supported_formats) + 1,
119cabdff1aSopenharmony_ci                                                    sizeof(*constraints->valid_sw_formats));
120cabdff1aSopenharmony_ci    if (!constraints->valid_sw_formats)
121cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
122cabdff1aSopenharmony_ci
123cabdff1aSopenharmony_ci    for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++)
124cabdff1aSopenharmony_ci        constraints->valid_sw_formats[i] = supported_formats[i];
125cabdff1aSopenharmony_ci    constraints->valid_sw_formats[FF_ARRAY_ELEMS(supported_formats)] = AV_PIX_FMT_NONE;
126cabdff1aSopenharmony_ci
127cabdff1aSopenharmony_ci    constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
128cabdff1aSopenharmony_ci    if (!constraints->valid_hw_formats)
129cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
130cabdff1aSopenharmony_ci
131cabdff1aSopenharmony_ci    constraints->valid_hw_formats[0] = AV_PIX_FMT_VIDEOTOOLBOX;
132cabdff1aSopenharmony_ci    constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
133cabdff1aSopenharmony_ci
134cabdff1aSopenharmony_ci    return 0;
135cabdff1aSopenharmony_ci}
136cabdff1aSopenharmony_ci
137cabdff1aSopenharmony_cienum AVPixelFormat av_map_videotoolbox_format_to_pixfmt(uint32_t cv_fmt)
138cabdff1aSopenharmony_ci{
139cabdff1aSopenharmony_ci    int i;
140cabdff1aSopenharmony_ci    for (i = 0; i < FF_ARRAY_ELEMS(cv_pix_fmts); i++) {
141cabdff1aSopenharmony_ci        if (cv_pix_fmts[i].cv_fmt == cv_fmt)
142cabdff1aSopenharmony_ci            return cv_pix_fmts[i].pix_fmt;
143cabdff1aSopenharmony_ci    }
144cabdff1aSopenharmony_ci    return AV_PIX_FMT_NONE;
145cabdff1aSopenharmony_ci}
146cabdff1aSopenharmony_ci
147cabdff1aSopenharmony_ciuint32_t av_map_videotoolbox_format_from_pixfmt(enum AVPixelFormat pix_fmt)
148cabdff1aSopenharmony_ci{
149cabdff1aSopenharmony_ci    return av_map_videotoolbox_format_from_pixfmt2(pix_fmt, false);
150cabdff1aSopenharmony_ci}
151cabdff1aSopenharmony_ci
152cabdff1aSopenharmony_ciuint32_t av_map_videotoolbox_format_from_pixfmt2(enum AVPixelFormat pix_fmt, bool full_range)
153cabdff1aSopenharmony_ci{
154cabdff1aSopenharmony_ci    int i;
155cabdff1aSopenharmony_ci    for (i = 0; i < FF_ARRAY_ELEMS(cv_pix_fmts); i++) {
156cabdff1aSopenharmony_ci        if (cv_pix_fmts[i].pix_fmt == pix_fmt && cv_pix_fmts[i].full_range == full_range)
157cabdff1aSopenharmony_ci            return cv_pix_fmts[i].cv_fmt;
158cabdff1aSopenharmony_ci    }
159cabdff1aSopenharmony_ci    return 0;
160cabdff1aSopenharmony_ci}
161cabdff1aSopenharmony_ci
162cabdff1aSopenharmony_cistatic int vt_pool_alloc(AVHWFramesContext *ctx)
163cabdff1aSopenharmony_ci{
164cabdff1aSopenharmony_ci    VTFramesContext *fctx = ctx->internal->priv;
165cabdff1aSopenharmony_ci    CVReturn err;
166cabdff1aSopenharmony_ci    CFNumberRef w, h, pixfmt;
167cabdff1aSopenharmony_ci    uint32_t cv_pixfmt;
168cabdff1aSopenharmony_ci    CFMutableDictionaryRef attributes, iosurface_properties;
169cabdff1aSopenharmony_ci
170cabdff1aSopenharmony_ci    attributes = CFDictionaryCreateMutable(
171cabdff1aSopenharmony_ci        NULL,
172cabdff1aSopenharmony_ci        2,
173cabdff1aSopenharmony_ci        &kCFTypeDictionaryKeyCallBacks,
174cabdff1aSopenharmony_ci        &kCFTypeDictionaryValueCallBacks);
175cabdff1aSopenharmony_ci
176cabdff1aSopenharmony_ci    cv_pixfmt = av_map_videotoolbox_format_from_pixfmt(ctx->sw_format);
177cabdff1aSopenharmony_ci    pixfmt = CFNumberCreate(NULL, kCFNumberSInt32Type, &cv_pixfmt);
178cabdff1aSopenharmony_ci    CFDictionarySetValue(
179cabdff1aSopenharmony_ci        attributes,
180cabdff1aSopenharmony_ci        kCVPixelBufferPixelFormatTypeKey,
181cabdff1aSopenharmony_ci        pixfmt);
182cabdff1aSopenharmony_ci    CFRelease(pixfmt);
183cabdff1aSopenharmony_ci
184cabdff1aSopenharmony_ci    iosurface_properties = CFDictionaryCreateMutable(
185cabdff1aSopenharmony_ci        NULL,
186cabdff1aSopenharmony_ci        0,
187cabdff1aSopenharmony_ci        &kCFTypeDictionaryKeyCallBacks,
188cabdff1aSopenharmony_ci        &kCFTypeDictionaryValueCallBacks);
189cabdff1aSopenharmony_ci    CFDictionarySetValue(attributes, kCVPixelBufferIOSurfacePropertiesKey, iosurface_properties);
190cabdff1aSopenharmony_ci    CFRelease(iosurface_properties);
191cabdff1aSopenharmony_ci
192cabdff1aSopenharmony_ci    w = CFNumberCreate(NULL, kCFNumberSInt32Type, &ctx->width);
193cabdff1aSopenharmony_ci    h = CFNumberCreate(NULL, kCFNumberSInt32Type, &ctx->height);
194cabdff1aSopenharmony_ci    CFDictionarySetValue(attributes, kCVPixelBufferWidthKey, w);
195cabdff1aSopenharmony_ci    CFDictionarySetValue(attributes, kCVPixelBufferHeightKey, h);
196cabdff1aSopenharmony_ci    CFRelease(w);
197cabdff1aSopenharmony_ci    CFRelease(h);
198cabdff1aSopenharmony_ci
199cabdff1aSopenharmony_ci    err = CVPixelBufferPoolCreate(
200cabdff1aSopenharmony_ci        NULL,
201cabdff1aSopenharmony_ci        NULL,
202cabdff1aSopenharmony_ci        attributes,
203cabdff1aSopenharmony_ci        &fctx->pool);
204cabdff1aSopenharmony_ci    CFRelease(attributes);
205cabdff1aSopenharmony_ci
206cabdff1aSopenharmony_ci    if (err == kCVReturnSuccess)
207cabdff1aSopenharmony_ci        return 0;
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci    av_log(ctx, AV_LOG_ERROR, "Error creating CVPixelBufferPool: %d\n", err);
210cabdff1aSopenharmony_ci    return AVERROR_EXTERNAL;
211cabdff1aSopenharmony_ci}
212cabdff1aSopenharmony_ci
213cabdff1aSopenharmony_cistatic void videotoolbox_buffer_release(void *opaque, uint8_t *data)
214cabdff1aSopenharmony_ci{
215cabdff1aSopenharmony_ci    CVPixelBufferRelease((CVPixelBufferRef)data);
216cabdff1aSopenharmony_ci}
217cabdff1aSopenharmony_ci
218cabdff1aSopenharmony_cistatic AVBufferRef *vt_pool_alloc_buffer(void *opaque, size_t size)
219cabdff1aSopenharmony_ci{
220cabdff1aSopenharmony_ci    CVPixelBufferRef pixbuf;
221cabdff1aSopenharmony_ci    AVBufferRef *buf;
222cabdff1aSopenharmony_ci    CVReturn err;
223cabdff1aSopenharmony_ci    AVHWFramesContext *ctx = opaque;
224cabdff1aSopenharmony_ci    VTFramesContext *fctx = ctx->internal->priv;
225cabdff1aSopenharmony_ci
226cabdff1aSopenharmony_ci    err = CVPixelBufferPoolCreatePixelBuffer(
227cabdff1aSopenharmony_ci        NULL,
228cabdff1aSopenharmony_ci        fctx->pool,
229cabdff1aSopenharmony_ci        &pixbuf
230cabdff1aSopenharmony_ci    );
231cabdff1aSopenharmony_ci    if (err != kCVReturnSuccess) {
232cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_ERROR, "Failed to create pixel buffer from pool: %d\n", err);
233cabdff1aSopenharmony_ci        return NULL;
234cabdff1aSopenharmony_ci    }
235cabdff1aSopenharmony_ci
236cabdff1aSopenharmony_ci    buf = av_buffer_create((uint8_t *)pixbuf, size,
237cabdff1aSopenharmony_ci                           videotoolbox_buffer_release, NULL, 0);
238cabdff1aSopenharmony_ci    if (!buf) {
239cabdff1aSopenharmony_ci        CVPixelBufferRelease(pixbuf);
240cabdff1aSopenharmony_ci        return NULL;
241cabdff1aSopenharmony_ci    }
242cabdff1aSopenharmony_ci    return buf;
243cabdff1aSopenharmony_ci}
244cabdff1aSopenharmony_ci
245cabdff1aSopenharmony_cistatic void vt_frames_uninit(AVHWFramesContext *ctx)
246cabdff1aSopenharmony_ci{
247cabdff1aSopenharmony_ci    VTFramesContext *fctx = ctx->internal->priv;
248cabdff1aSopenharmony_ci    if (fctx->pool) {
249cabdff1aSopenharmony_ci        CVPixelBufferPoolRelease(fctx->pool);
250cabdff1aSopenharmony_ci        fctx->pool = NULL;
251cabdff1aSopenharmony_ci    }
252cabdff1aSopenharmony_ci}
253cabdff1aSopenharmony_ci
254cabdff1aSopenharmony_cistatic int vt_frames_init(AVHWFramesContext *ctx)
255cabdff1aSopenharmony_ci{
256cabdff1aSopenharmony_ci    int i, ret;
257cabdff1aSopenharmony_ci
258cabdff1aSopenharmony_ci    for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
259cabdff1aSopenharmony_ci        if (ctx->sw_format == supported_formats[i])
260cabdff1aSopenharmony_ci            break;
261cabdff1aSopenharmony_ci    }
262cabdff1aSopenharmony_ci    if (i == FF_ARRAY_ELEMS(supported_formats)) {
263cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_ERROR, "Pixel format '%s' is not supported\n",
264cabdff1aSopenharmony_ci               av_get_pix_fmt_name(ctx->sw_format));
265cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
266cabdff1aSopenharmony_ci    }
267cabdff1aSopenharmony_ci
268cabdff1aSopenharmony_ci    if (!ctx->pool) {
269cabdff1aSopenharmony_ci        ctx->internal->pool_internal = av_buffer_pool_init2(
270cabdff1aSopenharmony_ci                sizeof(CVPixelBufferRef), ctx, vt_pool_alloc_buffer, NULL);
271cabdff1aSopenharmony_ci        if (!ctx->internal->pool_internal)
272cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
273cabdff1aSopenharmony_ci    }
274cabdff1aSopenharmony_ci
275cabdff1aSopenharmony_ci    ret = vt_pool_alloc(ctx);
276cabdff1aSopenharmony_ci    if (ret < 0)
277cabdff1aSopenharmony_ci        return ret;
278cabdff1aSopenharmony_ci
279cabdff1aSopenharmony_ci    return 0;
280cabdff1aSopenharmony_ci}
281cabdff1aSopenharmony_ci
282cabdff1aSopenharmony_cistatic int vt_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
283cabdff1aSopenharmony_ci{
284cabdff1aSopenharmony_ci    frame->buf[0] = av_buffer_pool_get(ctx->pool);
285cabdff1aSopenharmony_ci    if (!frame->buf[0])
286cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
287cabdff1aSopenharmony_ci
288cabdff1aSopenharmony_ci    frame->data[3] = frame->buf[0]->data;
289cabdff1aSopenharmony_ci    frame->format  = AV_PIX_FMT_VIDEOTOOLBOX;
290cabdff1aSopenharmony_ci    frame->width   = ctx->width;
291cabdff1aSopenharmony_ci    frame->height  = ctx->height;
292cabdff1aSopenharmony_ci
293cabdff1aSopenharmony_ci    return 0;
294cabdff1aSopenharmony_ci}
295cabdff1aSopenharmony_ci
296cabdff1aSopenharmony_cistatic int vt_transfer_get_formats(AVHWFramesContext *ctx,
297cabdff1aSopenharmony_ci                                   enum AVHWFrameTransferDirection dir,
298cabdff1aSopenharmony_ci                                   enum AVPixelFormat **formats)
299cabdff1aSopenharmony_ci{
300cabdff1aSopenharmony_ci    enum AVPixelFormat *fmts = av_malloc_array(2, sizeof(*fmts));
301cabdff1aSopenharmony_ci    if (!fmts)
302cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
303cabdff1aSopenharmony_ci
304cabdff1aSopenharmony_ci    fmts[0] = ctx->sw_format;
305cabdff1aSopenharmony_ci    fmts[1] = AV_PIX_FMT_NONE;
306cabdff1aSopenharmony_ci
307cabdff1aSopenharmony_ci    *formats = fmts;
308cabdff1aSopenharmony_ci    return 0;
309cabdff1aSopenharmony_ci}
310cabdff1aSopenharmony_ci
311cabdff1aSopenharmony_cistatic void vt_unmap(AVHWFramesContext *ctx, HWMapDescriptor *hwmap)
312cabdff1aSopenharmony_ci{
313cabdff1aSopenharmony_ci    CVPixelBufferRef pixbuf = (CVPixelBufferRef)hwmap->source->data[3];
314cabdff1aSopenharmony_ci
315cabdff1aSopenharmony_ci    CVPixelBufferUnlockBaseAddress(pixbuf, (uintptr_t)hwmap->priv);
316cabdff1aSopenharmony_ci}
317cabdff1aSopenharmony_ci
318cabdff1aSopenharmony_cistatic int vt_pixbuf_set_par(void *log_ctx,
319cabdff1aSopenharmony_ci                             CVPixelBufferRef pixbuf, const AVFrame *src)
320cabdff1aSopenharmony_ci{
321cabdff1aSopenharmony_ci    CFMutableDictionaryRef par = NULL;
322cabdff1aSopenharmony_ci    CFNumberRef num = NULL, den = NULL;
323cabdff1aSopenharmony_ci    AVRational avpar = src->sample_aspect_ratio;
324cabdff1aSopenharmony_ci
325cabdff1aSopenharmony_ci    if (avpar.num == 0)
326cabdff1aSopenharmony_ci        return 0;
327cabdff1aSopenharmony_ci
328cabdff1aSopenharmony_ci    av_reduce(&avpar.num, &avpar.den,
329cabdff1aSopenharmony_ci                avpar.num, avpar.den,
330cabdff1aSopenharmony_ci                0xFFFFFFFF);
331cabdff1aSopenharmony_ci
332cabdff1aSopenharmony_ci    num = CFNumberCreate(kCFAllocatorDefault,
333cabdff1aSopenharmony_ci                            kCFNumberIntType,
334cabdff1aSopenharmony_ci                            &avpar.num);
335cabdff1aSopenharmony_ci
336cabdff1aSopenharmony_ci    den = CFNumberCreate(kCFAllocatorDefault,
337cabdff1aSopenharmony_ci                            kCFNumberIntType,
338cabdff1aSopenharmony_ci                            &avpar.den);
339cabdff1aSopenharmony_ci
340cabdff1aSopenharmony_ci    par = CFDictionaryCreateMutable(kCFAllocatorDefault,
341cabdff1aSopenharmony_ci                                    2,
342cabdff1aSopenharmony_ci                                    &kCFCopyStringDictionaryKeyCallBacks,
343cabdff1aSopenharmony_ci                                    &kCFTypeDictionaryValueCallBacks);
344cabdff1aSopenharmony_ci
345cabdff1aSopenharmony_ci    if (!par || !num || !den) {
346cabdff1aSopenharmony_ci        if (par) CFRelease(par);
347cabdff1aSopenharmony_ci        if (num) CFRelease(num);
348cabdff1aSopenharmony_ci        if (den) CFRelease(den);
349cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
350cabdff1aSopenharmony_ci    }
351cabdff1aSopenharmony_ci
352cabdff1aSopenharmony_ci    CFDictionarySetValue(
353cabdff1aSopenharmony_ci        par,
354cabdff1aSopenharmony_ci        kCVImageBufferPixelAspectRatioHorizontalSpacingKey,
355cabdff1aSopenharmony_ci        num);
356cabdff1aSopenharmony_ci    CFDictionarySetValue(
357cabdff1aSopenharmony_ci        par,
358cabdff1aSopenharmony_ci        kCVImageBufferPixelAspectRatioVerticalSpacingKey,
359cabdff1aSopenharmony_ci        den);
360cabdff1aSopenharmony_ci
361cabdff1aSopenharmony_ci    CVBufferSetAttachment(
362cabdff1aSopenharmony_ci        pixbuf,
363cabdff1aSopenharmony_ci        kCVImageBufferPixelAspectRatioKey,
364cabdff1aSopenharmony_ci        par,
365cabdff1aSopenharmony_ci        kCVAttachmentMode_ShouldPropagate
366cabdff1aSopenharmony_ci    );
367cabdff1aSopenharmony_ci
368cabdff1aSopenharmony_ci    CFRelease(par);
369cabdff1aSopenharmony_ci    CFRelease(num);
370cabdff1aSopenharmony_ci    CFRelease(den);
371cabdff1aSopenharmony_ci
372cabdff1aSopenharmony_ci    return 0;
373cabdff1aSopenharmony_ci}
374cabdff1aSopenharmony_ci
375cabdff1aSopenharmony_ciCFStringRef av_map_videotoolbox_chroma_loc_from_av(enum AVChromaLocation loc)
376cabdff1aSopenharmony_ci{
377cabdff1aSopenharmony_ci    switch (loc) {
378cabdff1aSopenharmony_ci    case AVCHROMA_LOC_LEFT:
379cabdff1aSopenharmony_ci        return kCVImageBufferChromaLocation_Left;
380cabdff1aSopenharmony_ci    case AVCHROMA_LOC_CENTER:
381cabdff1aSopenharmony_ci        return kCVImageBufferChromaLocation_Center;
382cabdff1aSopenharmony_ci    case AVCHROMA_LOC_TOP:
383cabdff1aSopenharmony_ci        return kCVImageBufferChromaLocation_Top;
384cabdff1aSopenharmony_ci    case AVCHROMA_LOC_BOTTOM:
385cabdff1aSopenharmony_ci        return kCVImageBufferChromaLocation_Bottom;
386cabdff1aSopenharmony_ci    case AVCHROMA_LOC_TOPLEFT:
387cabdff1aSopenharmony_ci        return kCVImageBufferChromaLocation_TopLeft;
388cabdff1aSopenharmony_ci    case AVCHROMA_LOC_BOTTOMLEFT:
389cabdff1aSopenharmony_ci        return kCVImageBufferChromaLocation_BottomLeft;
390cabdff1aSopenharmony_ci    default:
391cabdff1aSopenharmony_ci        return NULL;
392cabdff1aSopenharmony_ci    }
393cabdff1aSopenharmony_ci}
394cabdff1aSopenharmony_ci
395cabdff1aSopenharmony_cistatic int vt_pixbuf_set_chromaloc(void *log_ctx,
396cabdff1aSopenharmony_ci                                   CVPixelBufferRef pixbuf, const AVFrame *src)
397cabdff1aSopenharmony_ci{
398cabdff1aSopenharmony_ci    CFStringRef loc = av_map_videotoolbox_chroma_loc_from_av(src->chroma_location);
399cabdff1aSopenharmony_ci
400cabdff1aSopenharmony_ci    if (loc) {
401cabdff1aSopenharmony_ci        CVBufferSetAttachment(
402cabdff1aSopenharmony_ci            pixbuf,
403cabdff1aSopenharmony_ci            kCVImageBufferChromaLocationTopFieldKey,
404cabdff1aSopenharmony_ci            loc,
405cabdff1aSopenharmony_ci            kCVAttachmentMode_ShouldPropagate);
406cabdff1aSopenharmony_ci    }
407cabdff1aSopenharmony_ci
408cabdff1aSopenharmony_ci    return 0;
409cabdff1aSopenharmony_ci}
410cabdff1aSopenharmony_ci
411cabdff1aSopenharmony_ciCFStringRef av_map_videotoolbox_color_matrix_from_av(enum AVColorSpace space)
412cabdff1aSopenharmony_ci{
413cabdff1aSopenharmony_ci    switch (space) {
414cabdff1aSopenharmony_ci    case AVCOL_SPC_BT2020_CL:
415cabdff1aSopenharmony_ci    case AVCOL_SPC_BT2020_NCL:
416cabdff1aSopenharmony_ci#if HAVE_KCVIMAGEBUFFERYCBCRMATRIX_ITU_R_2020
417cabdff1aSopenharmony_ci        if (__builtin_available(macOS 10.11, iOS 9, *))
418cabdff1aSopenharmony_ci            return kCVImageBufferYCbCrMatrix_ITU_R_2020;
419cabdff1aSopenharmony_ci#endif
420cabdff1aSopenharmony_ci        return CFSTR("ITU_R_2020");
421cabdff1aSopenharmony_ci    case AVCOL_SPC_BT470BG:
422cabdff1aSopenharmony_ci    case AVCOL_SPC_SMPTE170M:
423cabdff1aSopenharmony_ci        return kCVImageBufferYCbCrMatrix_ITU_R_601_4;
424cabdff1aSopenharmony_ci    case AVCOL_SPC_BT709:
425cabdff1aSopenharmony_ci        return kCVImageBufferYCbCrMatrix_ITU_R_709_2;
426cabdff1aSopenharmony_ci    case AVCOL_SPC_SMPTE240M:
427cabdff1aSopenharmony_ci        return kCVImageBufferYCbCrMatrix_SMPTE_240M_1995;
428cabdff1aSopenharmony_ci    default:
429cabdff1aSopenharmony_ci#if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
430cabdff1aSopenharmony_ci        if (__builtin_available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *))
431cabdff1aSopenharmony_ci            return CVYCbCrMatrixGetStringForIntegerCodePoint(space);
432cabdff1aSopenharmony_ci#endif
433cabdff1aSopenharmony_ci    case AVCOL_SPC_UNSPECIFIED:
434cabdff1aSopenharmony_ci        return NULL;
435cabdff1aSopenharmony_ci    }
436cabdff1aSopenharmony_ci}
437cabdff1aSopenharmony_ci
438cabdff1aSopenharmony_ciCFStringRef av_map_videotoolbox_color_primaries_from_av(enum AVColorPrimaries pri)
439cabdff1aSopenharmony_ci{
440cabdff1aSopenharmony_ci    switch (pri) {
441cabdff1aSopenharmony_ci    case AVCOL_PRI_BT2020:
442cabdff1aSopenharmony_ci#if HAVE_KCVIMAGEBUFFERCOLORPRIMARIES_ITU_R_2020
443cabdff1aSopenharmony_ci        if (__builtin_available(macOS 10.11, iOS 9, *))
444cabdff1aSopenharmony_ci            return kCVImageBufferColorPrimaries_ITU_R_2020;
445cabdff1aSopenharmony_ci#endif
446cabdff1aSopenharmony_ci        return CFSTR("ITU_R_2020");
447cabdff1aSopenharmony_ci    case AVCOL_PRI_BT709:
448cabdff1aSopenharmony_ci        return kCVImageBufferColorPrimaries_ITU_R_709_2;
449cabdff1aSopenharmony_ci    case AVCOL_PRI_SMPTE170M:
450cabdff1aSopenharmony_ci        return kCVImageBufferColorPrimaries_SMPTE_C;
451cabdff1aSopenharmony_ci    case AVCOL_PRI_BT470BG:
452cabdff1aSopenharmony_ci        return kCVImageBufferColorPrimaries_EBU_3213;
453cabdff1aSopenharmony_ci    default:
454cabdff1aSopenharmony_ci#if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
455cabdff1aSopenharmony_ci        if (__builtin_available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *))
456cabdff1aSopenharmony_ci            return CVColorPrimariesGetStringForIntegerCodePoint(pri);
457cabdff1aSopenharmony_ci#endif
458cabdff1aSopenharmony_ci    case AVCOL_PRI_UNSPECIFIED:
459cabdff1aSopenharmony_ci        return NULL;
460cabdff1aSopenharmony_ci    }
461cabdff1aSopenharmony_ci}
462cabdff1aSopenharmony_ci
463cabdff1aSopenharmony_ciCFStringRef av_map_videotoolbox_color_trc_from_av(enum AVColorTransferCharacteristic trc)
464cabdff1aSopenharmony_ci{
465cabdff1aSopenharmony_ci
466cabdff1aSopenharmony_ci    switch (trc) {
467cabdff1aSopenharmony_ci    case AVCOL_TRC_SMPTE2084:
468cabdff1aSopenharmony_ci#if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_2084_PQ
469cabdff1aSopenharmony_ci        if (__builtin_available(macOS 10.13, iOS 11, *))
470cabdff1aSopenharmony_ci            return kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ;
471cabdff1aSopenharmony_ci#endif
472cabdff1aSopenharmony_ci        return CFSTR("SMPTE_ST_2084_PQ");
473cabdff1aSopenharmony_ci    case AVCOL_TRC_BT2020_10:
474cabdff1aSopenharmony_ci    case AVCOL_TRC_BT2020_12:
475cabdff1aSopenharmony_ci#if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2020
476cabdff1aSopenharmony_ci        if (__builtin_available(macOS 10.11, iOS 9, *))
477cabdff1aSopenharmony_ci            return kCVImageBufferTransferFunction_ITU_R_2020;
478cabdff1aSopenharmony_ci#endif
479cabdff1aSopenharmony_ci        return CFSTR("ITU_R_2020");
480cabdff1aSopenharmony_ci    case AVCOL_TRC_BT709:
481cabdff1aSopenharmony_ci        return kCVImageBufferTransferFunction_ITU_R_709_2;
482cabdff1aSopenharmony_ci    case AVCOL_TRC_SMPTE240M:
483cabdff1aSopenharmony_ci        return kCVImageBufferTransferFunction_SMPTE_240M_1995;
484cabdff1aSopenharmony_ci    case AVCOL_TRC_SMPTE428:
485cabdff1aSopenharmony_ci#if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_428_1
486cabdff1aSopenharmony_ci        if (__builtin_available(macOS 10.12, iOS 10, *))
487cabdff1aSopenharmony_ci            return kCVImageBufferTransferFunction_SMPTE_ST_428_1;
488cabdff1aSopenharmony_ci#endif
489cabdff1aSopenharmony_ci        return CFSTR("SMPTE_ST_428_1");
490cabdff1aSopenharmony_ci    case AVCOL_TRC_ARIB_STD_B67:
491cabdff1aSopenharmony_ci#if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
492cabdff1aSopenharmony_ci        if (__builtin_available(macOS 10.13, iOS 11, *))
493cabdff1aSopenharmony_ci            return kCVImageBufferTransferFunction_ITU_R_2100_HLG;
494cabdff1aSopenharmony_ci#endif
495cabdff1aSopenharmony_ci        return CFSTR("ITU_R_2100_HLG");
496cabdff1aSopenharmony_ci    case AVCOL_TRC_GAMMA22:
497cabdff1aSopenharmony_ci        return kCVImageBufferTransferFunction_UseGamma;
498cabdff1aSopenharmony_ci    case AVCOL_TRC_GAMMA28:
499cabdff1aSopenharmony_ci        return kCVImageBufferTransferFunction_UseGamma;
500cabdff1aSopenharmony_ci    default:
501cabdff1aSopenharmony_ci#if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
502cabdff1aSopenharmony_ci        if (__builtin_available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *))
503cabdff1aSopenharmony_ci            return CVTransferFunctionGetStringForIntegerCodePoint(trc);
504cabdff1aSopenharmony_ci#endif
505cabdff1aSopenharmony_ci    case AVCOL_TRC_UNSPECIFIED:
506cabdff1aSopenharmony_ci        return NULL;
507cabdff1aSopenharmony_ci    }
508cabdff1aSopenharmony_ci}
509cabdff1aSopenharmony_ci
510cabdff1aSopenharmony_cistatic int vt_pixbuf_set_colorspace(void *log_ctx,
511cabdff1aSopenharmony_ci                                    CVPixelBufferRef pixbuf, const AVFrame *src)
512cabdff1aSopenharmony_ci{
513cabdff1aSopenharmony_ci    CFStringRef colormatrix = NULL, colorpri = NULL, colortrc = NULL;
514cabdff1aSopenharmony_ci    Float32 gamma = 0;
515cabdff1aSopenharmony_ci
516cabdff1aSopenharmony_ci    colormatrix = av_map_videotoolbox_color_matrix_from_av(src->colorspace);
517cabdff1aSopenharmony_ci    if (!colormatrix && src->colorspace != AVCOL_SPC_UNSPECIFIED)
518cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_WARNING, "Color space %s is not supported.\n", av_color_space_name(src->colorspace));
519cabdff1aSopenharmony_ci
520cabdff1aSopenharmony_ci    colorpri = av_map_videotoolbox_color_primaries_from_av(src->color_primaries);
521cabdff1aSopenharmony_ci    if (!colorpri && src->color_primaries != AVCOL_PRI_UNSPECIFIED)
522cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_WARNING, "Color primaries %s is not supported.\n", av_color_primaries_name(src->color_primaries));
523cabdff1aSopenharmony_ci
524cabdff1aSopenharmony_ci    colortrc = av_map_videotoolbox_color_trc_from_av(src->color_trc);
525cabdff1aSopenharmony_ci    if (!colortrc && src->color_trc != AVCOL_TRC_UNSPECIFIED)
526cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_WARNING, "Color transfer function %s is not supported.\n", av_color_transfer_name(src->color_trc));
527cabdff1aSopenharmony_ci
528cabdff1aSopenharmony_ci    if (src->color_trc == AVCOL_TRC_GAMMA22)
529cabdff1aSopenharmony_ci        gamma = 2.2;
530cabdff1aSopenharmony_ci    else if (src->color_trc == AVCOL_TRC_GAMMA28)
531cabdff1aSopenharmony_ci        gamma = 2.8;
532cabdff1aSopenharmony_ci
533cabdff1aSopenharmony_ci    if (colormatrix) {
534cabdff1aSopenharmony_ci        CVBufferSetAttachment(
535cabdff1aSopenharmony_ci            pixbuf,
536cabdff1aSopenharmony_ci            kCVImageBufferYCbCrMatrixKey,
537cabdff1aSopenharmony_ci            colormatrix,
538cabdff1aSopenharmony_ci            kCVAttachmentMode_ShouldPropagate);
539cabdff1aSopenharmony_ci    }
540cabdff1aSopenharmony_ci    if (colorpri) {
541cabdff1aSopenharmony_ci        CVBufferSetAttachment(
542cabdff1aSopenharmony_ci            pixbuf,
543cabdff1aSopenharmony_ci            kCVImageBufferColorPrimariesKey,
544cabdff1aSopenharmony_ci            colorpri,
545cabdff1aSopenharmony_ci            kCVAttachmentMode_ShouldPropagate);
546cabdff1aSopenharmony_ci    }
547cabdff1aSopenharmony_ci    if (colortrc) {
548cabdff1aSopenharmony_ci        CVBufferSetAttachment(
549cabdff1aSopenharmony_ci            pixbuf,
550cabdff1aSopenharmony_ci            kCVImageBufferTransferFunctionKey,
551cabdff1aSopenharmony_ci            colortrc,
552cabdff1aSopenharmony_ci            kCVAttachmentMode_ShouldPropagate);
553cabdff1aSopenharmony_ci    }
554cabdff1aSopenharmony_ci    if (gamma != 0) {
555cabdff1aSopenharmony_ci        CFNumberRef gamma_level = CFNumberCreate(NULL, kCFNumberFloat32Type, &gamma);
556cabdff1aSopenharmony_ci        CVBufferSetAttachment(
557cabdff1aSopenharmony_ci            pixbuf,
558cabdff1aSopenharmony_ci            kCVImageBufferGammaLevelKey,
559cabdff1aSopenharmony_ci            gamma_level,
560cabdff1aSopenharmony_ci            kCVAttachmentMode_ShouldPropagate);
561cabdff1aSopenharmony_ci        CFRelease(gamma_level);
562cabdff1aSopenharmony_ci    }
563cabdff1aSopenharmony_ci
564cabdff1aSopenharmony_ci    return 0;
565cabdff1aSopenharmony_ci}
566cabdff1aSopenharmony_ci
567cabdff1aSopenharmony_cistatic int vt_pixbuf_set_attachments(void *log_ctx,
568cabdff1aSopenharmony_ci                                     CVPixelBufferRef pixbuf, const AVFrame *src)
569cabdff1aSopenharmony_ci{
570cabdff1aSopenharmony_ci    int ret;
571cabdff1aSopenharmony_ci    ret = vt_pixbuf_set_par(log_ctx, pixbuf, src);
572cabdff1aSopenharmony_ci    if (ret < 0)
573cabdff1aSopenharmony_ci        return ret;
574cabdff1aSopenharmony_ci    ret = vt_pixbuf_set_colorspace(log_ctx, pixbuf, src);
575cabdff1aSopenharmony_ci    if (ret < 0)
576cabdff1aSopenharmony_ci        return ret;
577cabdff1aSopenharmony_ci    ret = vt_pixbuf_set_chromaloc(log_ctx, pixbuf, src);
578cabdff1aSopenharmony_ci    if (ret < 0)
579cabdff1aSopenharmony_ci        return ret;
580cabdff1aSopenharmony_ci    return 0;
581cabdff1aSopenharmony_ci}
582cabdff1aSopenharmony_ci
583cabdff1aSopenharmony_ciint av_vt_pixbuf_set_attachments(void *log_ctx,
584cabdff1aSopenharmony_ci                                 CVPixelBufferRef pixbuf, const AVFrame *src)
585cabdff1aSopenharmony_ci{
586cabdff1aSopenharmony_ci    return vt_pixbuf_set_attachments(log_ctx, pixbuf, src);
587cabdff1aSopenharmony_ci}
588cabdff1aSopenharmony_ci
589cabdff1aSopenharmony_cistatic int vt_map_frame(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src,
590cabdff1aSopenharmony_ci                        int flags)
591cabdff1aSopenharmony_ci{
592cabdff1aSopenharmony_ci    CVPixelBufferRef pixbuf = (CVPixelBufferRef)src->data[3];
593cabdff1aSopenharmony_ci    OSType pixel_format = CVPixelBufferGetPixelFormatType(pixbuf);
594cabdff1aSopenharmony_ci    CVReturn err;
595cabdff1aSopenharmony_ci    uint32_t map_flags = 0;
596cabdff1aSopenharmony_ci    int ret;
597cabdff1aSopenharmony_ci    int i;
598cabdff1aSopenharmony_ci    enum AVPixelFormat format;
599cabdff1aSopenharmony_ci
600cabdff1aSopenharmony_ci    format = av_map_videotoolbox_format_to_pixfmt(pixel_format);
601cabdff1aSopenharmony_ci    if (dst->format != format) {
602cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_ERROR, "Unsupported or mismatching pixel format: %s\n",
603cabdff1aSopenharmony_ci               av_fourcc2str(pixel_format));
604cabdff1aSopenharmony_ci        return AVERROR_UNKNOWN;
605cabdff1aSopenharmony_ci    }
606cabdff1aSopenharmony_ci
607cabdff1aSopenharmony_ci    if (CVPixelBufferGetWidth(pixbuf) != ctx->width ||
608cabdff1aSopenharmony_ci        CVPixelBufferGetHeight(pixbuf) != ctx->height) {
609cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_ERROR, "Inconsistent frame dimensions.\n");
610cabdff1aSopenharmony_ci        return AVERROR_UNKNOWN;
611cabdff1aSopenharmony_ci    }
612cabdff1aSopenharmony_ci
613cabdff1aSopenharmony_ci    if (flags == AV_HWFRAME_MAP_READ)
614cabdff1aSopenharmony_ci        map_flags = kCVPixelBufferLock_ReadOnly;
615cabdff1aSopenharmony_ci
616cabdff1aSopenharmony_ci    err = CVPixelBufferLockBaseAddress(pixbuf, map_flags);
617cabdff1aSopenharmony_ci    if (err != kCVReturnSuccess) {
618cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_ERROR, "Error locking the pixel buffer.\n");
619cabdff1aSopenharmony_ci        return AVERROR_UNKNOWN;
620cabdff1aSopenharmony_ci    }
621cabdff1aSopenharmony_ci
622cabdff1aSopenharmony_ci    if (CVPixelBufferIsPlanar(pixbuf)) {
623cabdff1aSopenharmony_ci        int planes = CVPixelBufferGetPlaneCount(pixbuf);
624cabdff1aSopenharmony_ci        for (i = 0; i < planes; i++) {
625cabdff1aSopenharmony_ci            dst->data[i]     = CVPixelBufferGetBaseAddressOfPlane(pixbuf, i);
626cabdff1aSopenharmony_ci            dst->linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf, i);
627cabdff1aSopenharmony_ci        }
628cabdff1aSopenharmony_ci    } else {
629cabdff1aSopenharmony_ci        dst->data[0]     = CVPixelBufferGetBaseAddress(pixbuf);
630cabdff1aSopenharmony_ci        dst->linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf);
631cabdff1aSopenharmony_ci    }
632cabdff1aSopenharmony_ci
633cabdff1aSopenharmony_ci    ret = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, vt_unmap,
634cabdff1aSopenharmony_ci                                (void *)(uintptr_t)map_flags);
635cabdff1aSopenharmony_ci    if (ret < 0)
636cabdff1aSopenharmony_ci        goto unlock;
637cabdff1aSopenharmony_ci
638cabdff1aSopenharmony_ci    return 0;
639cabdff1aSopenharmony_ci
640cabdff1aSopenharmony_ciunlock:
641cabdff1aSopenharmony_ci    CVPixelBufferUnlockBaseAddress(pixbuf, map_flags);
642cabdff1aSopenharmony_ci    return ret;
643cabdff1aSopenharmony_ci}
644cabdff1aSopenharmony_ci
645cabdff1aSopenharmony_cistatic int vt_transfer_data_from(AVHWFramesContext *hwfc,
646cabdff1aSopenharmony_ci                                 AVFrame *dst, const AVFrame *src)
647cabdff1aSopenharmony_ci{
648cabdff1aSopenharmony_ci    AVFrame *map;
649cabdff1aSopenharmony_ci    int err;
650cabdff1aSopenharmony_ci
651cabdff1aSopenharmony_ci    if (dst->width > hwfc->width || dst->height > hwfc->height)
652cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
653cabdff1aSopenharmony_ci
654cabdff1aSopenharmony_ci    map = av_frame_alloc();
655cabdff1aSopenharmony_ci    if (!map)
656cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
657cabdff1aSopenharmony_ci    map->format = dst->format;
658cabdff1aSopenharmony_ci
659cabdff1aSopenharmony_ci    err = vt_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
660cabdff1aSopenharmony_ci    if (err)
661cabdff1aSopenharmony_ci        goto fail;
662cabdff1aSopenharmony_ci
663cabdff1aSopenharmony_ci    map->width  = dst->width;
664cabdff1aSopenharmony_ci    map->height = dst->height;
665cabdff1aSopenharmony_ci
666cabdff1aSopenharmony_ci    err = av_frame_copy(dst, map);
667cabdff1aSopenharmony_ci    if (err)
668cabdff1aSopenharmony_ci        goto fail;
669cabdff1aSopenharmony_ci
670cabdff1aSopenharmony_ci    err = 0;
671cabdff1aSopenharmony_cifail:
672cabdff1aSopenharmony_ci    av_frame_free(&map);
673cabdff1aSopenharmony_ci    return err;
674cabdff1aSopenharmony_ci}
675cabdff1aSopenharmony_ci
676cabdff1aSopenharmony_cistatic int vt_transfer_data_to(AVHWFramesContext *hwfc,
677cabdff1aSopenharmony_ci                               AVFrame *dst, const AVFrame *src)
678cabdff1aSopenharmony_ci{
679cabdff1aSopenharmony_ci    AVFrame *map;
680cabdff1aSopenharmony_ci    int err;
681cabdff1aSopenharmony_ci
682cabdff1aSopenharmony_ci    if (src->width > hwfc->width || src->height > hwfc->height)
683cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
684cabdff1aSopenharmony_ci
685cabdff1aSopenharmony_ci    map = av_frame_alloc();
686cabdff1aSopenharmony_ci    if (!map)
687cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
688cabdff1aSopenharmony_ci    map->format = src->format;
689cabdff1aSopenharmony_ci
690cabdff1aSopenharmony_ci    err = vt_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
691cabdff1aSopenharmony_ci    if (err)
692cabdff1aSopenharmony_ci        goto fail;
693cabdff1aSopenharmony_ci
694cabdff1aSopenharmony_ci    map->width  = src->width;
695cabdff1aSopenharmony_ci    map->height = src->height;
696cabdff1aSopenharmony_ci
697cabdff1aSopenharmony_ci    err = av_frame_copy(map, src);
698cabdff1aSopenharmony_ci    if (err)
699cabdff1aSopenharmony_ci        goto fail;
700cabdff1aSopenharmony_ci
701cabdff1aSopenharmony_ci    err = vt_pixbuf_set_attachments(hwfc, (CVPixelBufferRef)dst->data[3], src);
702cabdff1aSopenharmony_ci    if (err)
703cabdff1aSopenharmony_ci        goto fail;
704cabdff1aSopenharmony_ci
705cabdff1aSopenharmony_ci    err = 0;
706cabdff1aSopenharmony_cifail:
707cabdff1aSopenharmony_ci    av_frame_free(&map);
708cabdff1aSopenharmony_ci    return err;
709cabdff1aSopenharmony_ci}
710cabdff1aSopenharmony_ci
711cabdff1aSopenharmony_cistatic int vt_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
712cabdff1aSopenharmony_ci                       const AVFrame *src, int flags)
713cabdff1aSopenharmony_ci{
714cabdff1aSopenharmony_ci    int err;
715cabdff1aSopenharmony_ci
716cabdff1aSopenharmony_ci    if (dst->format == AV_PIX_FMT_NONE)
717cabdff1aSopenharmony_ci        dst->format = hwfc->sw_format;
718cabdff1aSopenharmony_ci    else if (dst->format != hwfc->sw_format)
719cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
720cabdff1aSopenharmony_ci
721cabdff1aSopenharmony_ci    err = vt_map_frame(hwfc, dst, src, flags);
722cabdff1aSopenharmony_ci    if (err)
723cabdff1aSopenharmony_ci        return err;
724cabdff1aSopenharmony_ci
725cabdff1aSopenharmony_ci    dst->width  = src->width;
726cabdff1aSopenharmony_ci    dst->height = src->height;
727cabdff1aSopenharmony_ci
728cabdff1aSopenharmony_ci    err = av_frame_copy_props(dst, src);
729cabdff1aSopenharmony_ci    if (err)
730cabdff1aSopenharmony_ci        return err;
731cabdff1aSopenharmony_ci
732cabdff1aSopenharmony_ci    return 0;
733cabdff1aSopenharmony_ci}
734cabdff1aSopenharmony_ci
735cabdff1aSopenharmony_cistatic int vt_device_create(AVHWDeviceContext *ctx, const char *device,
736cabdff1aSopenharmony_ci                            AVDictionary *opts, int flags)
737cabdff1aSopenharmony_ci{
738cabdff1aSopenharmony_ci    if (device && device[0]) {
739cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_ERROR, "Device selection unsupported.\n");
740cabdff1aSopenharmony_ci        return AVERROR_UNKNOWN;
741cabdff1aSopenharmony_ci    }
742cabdff1aSopenharmony_ci
743cabdff1aSopenharmony_ci    return 0;
744cabdff1aSopenharmony_ci}
745cabdff1aSopenharmony_ci
746cabdff1aSopenharmony_ciconst HWContextType ff_hwcontext_type_videotoolbox = {
747cabdff1aSopenharmony_ci    .type                 = AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
748cabdff1aSopenharmony_ci    .name                 = "videotoolbox",
749cabdff1aSopenharmony_ci
750cabdff1aSopenharmony_ci    .frames_priv_size     = sizeof(VTFramesContext),
751cabdff1aSopenharmony_ci
752cabdff1aSopenharmony_ci    .device_create        = vt_device_create,
753cabdff1aSopenharmony_ci    .frames_init          = vt_frames_init,
754cabdff1aSopenharmony_ci    .frames_get_buffer    = vt_get_buffer,
755cabdff1aSopenharmony_ci    .frames_get_constraints = vt_frames_get_constraints,
756cabdff1aSopenharmony_ci    .frames_uninit        = vt_frames_uninit,
757cabdff1aSopenharmony_ci    .transfer_get_formats = vt_transfer_get_formats,
758cabdff1aSopenharmony_ci    .transfer_data_to     = vt_transfer_data_to,
759cabdff1aSopenharmony_ci    .transfer_data_from   = vt_transfer_data_from,
760cabdff1aSopenharmony_ci    .map_from             = vt_map_from,
761cabdff1aSopenharmony_ci
762cabdff1aSopenharmony_ci    .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_VIDEOTOOLBOX, AV_PIX_FMT_NONE },
763cabdff1aSopenharmony_ci};
764