Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
52867 views
1
/*
2
* This file is part of FFmpeg.
3
*
4
* FFmpeg is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2.1 of the License, or (at your option) any later version.
8
*
9
* FFmpeg is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
13
*
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with FFmpeg; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
*/
18
19
#include "config.h"
20
21
#if HAVE_UTGETOSTYPEFROMSTRING
22
#include <CoreServices/CoreServices.h>
23
#endif
24
25
#include "libavcodec/avcodec.h"
26
#if CONFIG_VDA
27
# include "libavcodec/vda.h"
28
#endif
29
#if CONFIG_VIDEOTOOLBOX
30
# include "libavcodec/videotoolbox.h"
31
#endif
32
#include "libavutil/imgutils.h"
33
#include "ffmpeg.h"
34
35
typedef struct VTContext {
36
AVFrame *tmp_frame;
37
} VTContext;
38
39
char *videotoolbox_pixfmt;
40
41
static int videotoolbox_retrieve_data(AVCodecContext *s, AVFrame *frame)
42
{
43
InputStream *ist = s->opaque;
44
VTContext *vt = ist->hwaccel_ctx;
45
CVPixelBufferRef pixbuf = (CVPixelBufferRef)frame->data[3];
46
OSType pixel_format = CVPixelBufferGetPixelFormatType(pixbuf);
47
CVReturn err;
48
uint8_t *data[4] = { 0 };
49
int linesize[4] = { 0 };
50
int planes, ret, i;
51
char codec_str[32];
52
53
av_frame_unref(vt->tmp_frame);
54
55
switch (pixel_format) {
56
case kCVPixelFormatType_420YpCbCr8Planar: vt->tmp_frame->format = AV_PIX_FMT_YUV420P; break;
57
case kCVPixelFormatType_422YpCbCr8: vt->tmp_frame->format = AV_PIX_FMT_UYVY422; break;
58
case kCVPixelFormatType_32BGRA: vt->tmp_frame->format = AV_PIX_FMT_BGRA; break;
59
#ifdef kCFCoreFoundationVersionNumber10_7
60
case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: vt->tmp_frame->format = AV_PIX_FMT_NV12; break;
61
#endif
62
default:
63
av_get_codec_tag_string(codec_str, sizeof(codec_str), s->codec_tag);
64
av_log(NULL, AV_LOG_ERROR,
65
"%s: Unsupported pixel format: %s\n", codec_str, videotoolbox_pixfmt);
66
return AVERROR(ENOSYS);
67
}
68
69
vt->tmp_frame->width = frame->width;
70
vt->tmp_frame->height = frame->height;
71
ret = av_frame_get_buffer(vt->tmp_frame, 32);
72
if (ret < 0)
73
return ret;
74
75
err = CVPixelBufferLockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly);
76
if (err != kCVReturnSuccess) {
77
av_log(NULL, AV_LOG_ERROR, "Error locking the pixel buffer.\n");
78
return AVERROR_UNKNOWN;
79
}
80
81
if (CVPixelBufferIsPlanar(pixbuf)) {
82
83
planes = CVPixelBufferGetPlaneCount(pixbuf);
84
for (i = 0; i < planes; i++) {
85
data[i] = CVPixelBufferGetBaseAddressOfPlane(pixbuf, i);
86
linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf, i);
87
}
88
} else {
89
data[0] = CVPixelBufferGetBaseAddress(pixbuf);
90
linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf);
91
}
92
93
av_image_copy(vt->tmp_frame->data, vt->tmp_frame->linesize,
94
(const uint8_t **)data, linesize, vt->tmp_frame->format,
95
frame->width, frame->height);
96
97
ret = av_frame_copy_props(vt->tmp_frame, frame);
98
CVPixelBufferUnlockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly);
99
if (ret < 0)
100
return ret;
101
102
av_frame_unref(frame);
103
av_frame_move_ref(frame, vt->tmp_frame);
104
105
return 0;
106
}
107
108
static void videotoolbox_uninit(AVCodecContext *s)
109
{
110
InputStream *ist = s->opaque;
111
VTContext *vt = ist->hwaccel_ctx;
112
113
ist->hwaccel_uninit = NULL;
114
ist->hwaccel_retrieve_data = NULL;
115
116
av_frame_free(&vt->tmp_frame);
117
118
if (ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX) {
119
#if CONFIG_VIDEOTOOLBOX
120
av_videotoolbox_default_free(s);
121
#endif
122
} else {
123
#if CONFIG_VDA
124
av_vda_default_free(s);
125
#endif
126
}
127
av_freep(&ist->hwaccel_ctx);
128
}
129
130
int videotoolbox_init(AVCodecContext *s)
131
{
132
InputStream *ist = s->opaque;
133
int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
134
int ret = 0;
135
VTContext *vt;
136
137
vt = av_mallocz(sizeof(*vt));
138
if (!vt)
139
return AVERROR(ENOMEM);
140
141
ist->hwaccel_ctx = vt;
142
ist->hwaccel_uninit = videotoolbox_uninit;
143
ist->hwaccel_retrieve_data = videotoolbox_retrieve_data;
144
145
vt->tmp_frame = av_frame_alloc();
146
if (!vt->tmp_frame) {
147
ret = AVERROR(ENOMEM);
148
goto fail;
149
}
150
151
if (ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX) {
152
#if CONFIG_VIDEOTOOLBOX
153
if (!videotoolbox_pixfmt) {
154
ret = av_videotoolbox_default_init(s);
155
} else {
156
AVVideotoolboxContext *vtctx = av_videotoolbox_alloc_context();
157
CFStringRef pixfmt_str = CFStringCreateWithCString(kCFAllocatorDefault,
158
videotoolbox_pixfmt,
159
kCFStringEncodingUTF8);
160
#if HAVE_UTGETOSTYPEFROMSTRING
161
vtctx->cv_pix_fmt_type = UTGetOSTypeFromString(pixfmt_str);
162
#else
163
av_log(s, loglevel, "UTGetOSTypeFromString() is not available "
164
"on this platform, %s pixel format can not be honored from "
165
"the command line\n", videotoolbox_pixfmt);
166
#endif
167
ret = av_videotoolbox_default_init2(s, vtctx);
168
CFRelease(pixfmt_str);
169
}
170
#endif
171
} else {
172
#if CONFIG_VDA
173
if (!videotoolbox_pixfmt) {
174
ret = av_vda_default_init(s);
175
} else {
176
AVVDAContext *vdactx = av_vda_alloc_context();
177
CFStringRef pixfmt_str = CFStringCreateWithCString(kCFAllocatorDefault,
178
videotoolbox_pixfmt,
179
kCFStringEncodingUTF8);
180
#if HAVE_UTGETOSTYPEFROMSTRING
181
vdactx->cv_pix_fmt_type = UTGetOSTypeFromString(pixfmt_str);
182
#else
183
av_log(s, loglevel, "UTGetOSTypeFromString() is not available "
184
"on this platform, %s pixel format can not be honored from "
185
"the command line\n", videotoolbox_pixfmt);
186
#endif
187
ret = av_vda_default_init2(s, vdactx);
188
CFRelease(pixfmt_str);
189
}
190
#endif
191
}
192
if (ret < 0) {
193
av_log(NULL, loglevel,
194
"Error creating %s decoder.\n", ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX ? "Videotoolbox" : "VDA");
195
goto fail;
196
}
197
198
return 0;
199
fail:
200
videotoolbox_uninit(s);
201
return ret;
202
}
203
204