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#if HAVE_UTGETOSTYPEFROMSTRING
22cabdff1aSopenharmony_ci#include <CoreServices/CoreServices.h>
23cabdff1aSopenharmony_ci#endif
24cabdff1aSopenharmony_ci
25cabdff1aSopenharmony_ci#include "libavcodec/avcodec.h"
26cabdff1aSopenharmony_ci#include "libavcodec/videotoolbox.h"
27cabdff1aSopenharmony_ci#include "libavutil/imgutils.h"
28cabdff1aSopenharmony_ci#include "ffmpeg.h"
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_citypedef struct VTContext {
31cabdff1aSopenharmony_ci    AVFrame *tmp_frame;
32cabdff1aSopenharmony_ci} VTContext;
33cabdff1aSopenharmony_ci
34cabdff1aSopenharmony_cichar *videotoolbox_pixfmt;
35cabdff1aSopenharmony_ci
36cabdff1aSopenharmony_cistatic int videotoolbox_retrieve_data(AVCodecContext *s, AVFrame *frame)
37cabdff1aSopenharmony_ci{
38cabdff1aSopenharmony_ci    InputStream *ist = s->opaque;
39cabdff1aSopenharmony_ci    VTContext  *vt = ist->hwaccel_ctx;
40cabdff1aSopenharmony_ci    CVPixelBufferRef pixbuf = (CVPixelBufferRef)frame->data[3];
41cabdff1aSopenharmony_ci    OSType pixel_format = CVPixelBufferGetPixelFormatType(pixbuf);
42cabdff1aSopenharmony_ci    CVReturn err;
43cabdff1aSopenharmony_ci    uint8_t *data[4] = { 0 };
44cabdff1aSopenharmony_ci    int linesize[4] = { 0 };
45cabdff1aSopenharmony_ci    int planes, ret, i;
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_ci    av_frame_unref(vt->tmp_frame);
48cabdff1aSopenharmony_ci
49cabdff1aSopenharmony_ci    switch (pixel_format) {
50cabdff1aSopenharmony_ci    case kCVPixelFormatType_420YpCbCr8Planar: vt->tmp_frame->format = AV_PIX_FMT_YUV420P; break;
51cabdff1aSopenharmony_ci    case kCVPixelFormatType_422YpCbCr8:       vt->tmp_frame->format = AV_PIX_FMT_UYVY422; break;
52cabdff1aSopenharmony_ci    case kCVPixelFormatType_32BGRA:           vt->tmp_frame->format = AV_PIX_FMT_BGRA; break;
53cabdff1aSopenharmony_ci#ifdef kCFCoreFoundationVersionNumber10_7
54cabdff1aSopenharmony_ci    case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
55cabdff1aSopenharmony_ci    case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange: vt->tmp_frame->format = AV_PIX_FMT_NV12; break;
56cabdff1aSopenharmony_ci#endif
57cabdff1aSopenharmony_ci#if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
58cabdff1aSopenharmony_ci    case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
59cabdff1aSopenharmony_ci    case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange: vt->tmp_frame->format = AV_PIX_FMT_P010; break;
60cabdff1aSopenharmony_ci#endif
61cabdff1aSopenharmony_ci    default:
62cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR,
63cabdff1aSopenharmony_ci               "%s: Unsupported pixel format: %s\n",
64cabdff1aSopenharmony_ci               av_fourcc2str(s->codec_tag), videotoolbox_pixfmt);
65cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
66cabdff1aSopenharmony_ci    }
67cabdff1aSopenharmony_ci
68cabdff1aSopenharmony_ci    vt->tmp_frame->width  = frame->width;
69cabdff1aSopenharmony_ci    vt->tmp_frame->height = frame->height;
70cabdff1aSopenharmony_ci    ret = av_frame_get_buffer(vt->tmp_frame, 0);
71cabdff1aSopenharmony_ci    if (ret < 0)
72cabdff1aSopenharmony_ci        return ret;
73cabdff1aSopenharmony_ci
74cabdff1aSopenharmony_ci    err = CVPixelBufferLockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly);
75cabdff1aSopenharmony_ci    if (err != kCVReturnSuccess) {
76cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Error locking the pixel buffer.\n");
77cabdff1aSopenharmony_ci        return AVERROR_UNKNOWN;
78cabdff1aSopenharmony_ci    }
79cabdff1aSopenharmony_ci
80cabdff1aSopenharmony_ci    if (CVPixelBufferIsPlanar(pixbuf)) {
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_ci        planes = CVPixelBufferGetPlaneCount(pixbuf);
83cabdff1aSopenharmony_ci        for (i = 0; i < planes; i++) {
84cabdff1aSopenharmony_ci            data[i]     = CVPixelBufferGetBaseAddressOfPlane(pixbuf, i);
85cabdff1aSopenharmony_ci            linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf, i);
86cabdff1aSopenharmony_ci        }
87cabdff1aSopenharmony_ci    } else {
88cabdff1aSopenharmony_ci        data[0] = CVPixelBufferGetBaseAddress(pixbuf);
89cabdff1aSopenharmony_ci        linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf);
90cabdff1aSopenharmony_ci    }
91cabdff1aSopenharmony_ci
92cabdff1aSopenharmony_ci    av_image_copy(vt->tmp_frame->data, vt->tmp_frame->linesize,
93cabdff1aSopenharmony_ci                  (const uint8_t **)data, linesize, vt->tmp_frame->format,
94cabdff1aSopenharmony_ci                  frame->width, frame->height);
95cabdff1aSopenharmony_ci
96cabdff1aSopenharmony_ci    ret = av_frame_copy_props(vt->tmp_frame, frame);
97cabdff1aSopenharmony_ci    CVPixelBufferUnlockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly);
98cabdff1aSopenharmony_ci    if (ret < 0)
99cabdff1aSopenharmony_ci        return ret;
100cabdff1aSopenharmony_ci
101cabdff1aSopenharmony_ci    av_frame_unref(frame);
102cabdff1aSopenharmony_ci    av_frame_move_ref(frame, vt->tmp_frame);
103cabdff1aSopenharmony_ci
104cabdff1aSopenharmony_ci    return 0;
105cabdff1aSopenharmony_ci}
106cabdff1aSopenharmony_ci
107cabdff1aSopenharmony_cistatic void videotoolbox_uninit(AVCodecContext *s)
108cabdff1aSopenharmony_ci{
109cabdff1aSopenharmony_ci    InputStream *ist = s->opaque;
110cabdff1aSopenharmony_ci    VTContext  *vt = ist->hwaccel_ctx;
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_ci    ist->hwaccel_uninit        = NULL;
113cabdff1aSopenharmony_ci    ist->hwaccel_retrieve_data = NULL;
114cabdff1aSopenharmony_ci
115cabdff1aSopenharmony_ci    av_frame_free(&vt->tmp_frame);
116cabdff1aSopenharmony_ci
117cabdff1aSopenharmony_ci    av_videotoolbox_default_free(s);
118cabdff1aSopenharmony_ci    av_freep(&ist->hwaccel_ctx);
119cabdff1aSopenharmony_ci}
120cabdff1aSopenharmony_ci
121cabdff1aSopenharmony_ciint videotoolbox_init(AVCodecContext *s)
122cabdff1aSopenharmony_ci{
123cabdff1aSopenharmony_ci    InputStream *ist = s->opaque;
124cabdff1aSopenharmony_ci    int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
125cabdff1aSopenharmony_ci    int ret = 0;
126cabdff1aSopenharmony_ci    VTContext *vt;
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci    vt = av_mallocz(sizeof(*vt));
129cabdff1aSopenharmony_ci    if (!vt)
130cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
131cabdff1aSopenharmony_ci
132cabdff1aSopenharmony_ci    ist->hwaccel_ctx           = vt;
133cabdff1aSopenharmony_ci    ist->hwaccel_uninit        = videotoolbox_uninit;
134cabdff1aSopenharmony_ci    ist->hwaccel_retrieve_data = videotoolbox_retrieve_data;
135cabdff1aSopenharmony_ci
136cabdff1aSopenharmony_ci    vt->tmp_frame = av_frame_alloc();
137cabdff1aSopenharmony_ci    if (!vt->tmp_frame) {
138cabdff1aSopenharmony_ci        ret = AVERROR(ENOMEM);
139cabdff1aSopenharmony_ci        goto fail;
140cabdff1aSopenharmony_ci    }
141cabdff1aSopenharmony_ci
142cabdff1aSopenharmony_ci    // TODO: reindent
143cabdff1aSopenharmony_ci        if (!videotoolbox_pixfmt) {
144cabdff1aSopenharmony_ci            ret = av_videotoolbox_default_init(s);
145cabdff1aSopenharmony_ci        } else {
146cabdff1aSopenharmony_ci            AVVideotoolboxContext *vtctx = av_videotoolbox_alloc_context();
147cabdff1aSopenharmony_ci            CFStringRef pixfmt_str = CFStringCreateWithCString(kCFAllocatorDefault,
148cabdff1aSopenharmony_ci                                                               videotoolbox_pixfmt,
149cabdff1aSopenharmony_ci                                                               kCFStringEncodingUTF8);
150cabdff1aSopenharmony_ci#if HAVE_UTGETOSTYPEFROMSTRING
151cabdff1aSopenharmony_ci            vtctx->cv_pix_fmt_type = UTGetOSTypeFromString(pixfmt_str);
152cabdff1aSopenharmony_ci#else
153cabdff1aSopenharmony_ci            av_log(s, loglevel, "UTGetOSTypeFromString() is not available "
154cabdff1aSopenharmony_ci                   "on this platform, %s pixel format can not be honored from "
155cabdff1aSopenharmony_ci                   "the command line\n", videotoolbox_pixfmt);
156cabdff1aSopenharmony_ci#endif
157cabdff1aSopenharmony_ci            ret = av_videotoolbox_default_init2(s, vtctx);
158cabdff1aSopenharmony_ci            CFRelease(pixfmt_str);
159cabdff1aSopenharmony_ci        }
160cabdff1aSopenharmony_ci    if (ret < 0) {
161cabdff1aSopenharmony_ci        av_log(NULL, loglevel, "Error creating Videotoolbox decoder.\n");
162cabdff1aSopenharmony_ci        goto fail;
163cabdff1aSopenharmony_ci    }
164cabdff1aSopenharmony_ci
165cabdff1aSopenharmony_ci    return 0;
166cabdff1aSopenharmony_cifail:
167cabdff1aSopenharmony_ci    videotoolbox_uninit(s);
168cabdff1aSopenharmony_ci    return ret;
169cabdff1aSopenharmony_ci}
170