blob: e9039654b93de84cfb1fe4c1387dc036fa777249
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 | |
52 | av_frame_unref(vt->tmp_frame); |
53 | |
54 | switch (pixel_format) { |
55 | case kCVPixelFormatType_420YpCbCr8Planar: vt->tmp_frame->format = AV_PIX_FMT_YUV420P; break; |
56 | case kCVPixelFormatType_422YpCbCr8: vt->tmp_frame->format = AV_PIX_FMT_UYVY422; break; |
57 | case kCVPixelFormatType_32BGRA: vt->tmp_frame->format = AV_PIX_FMT_BGRA; break; |
58 | #ifdef kCFCoreFoundationVersionNumber10_7 |
59 | case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: vt->tmp_frame->format = AV_PIX_FMT_NV12; break; |
60 | #endif |
61 | default: |
62 | av_log(NULL, AV_LOG_ERROR, |
63 | "%s: Unsupported pixel format: %s\n", |
64 | av_fourcc2str(s->codec_tag), videotoolbox_pixfmt); |
65 | return AVERROR(ENOSYS); |
66 | } |
67 | |
68 | vt->tmp_frame->width = frame->width; |
69 | vt->tmp_frame->height = frame->height; |
70 | ret = av_frame_get_buffer(vt->tmp_frame, 32); |
71 | if (ret < 0) |
72 | return ret; |
73 | |
74 | err = CVPixelBufferLockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly); |
75 | if (err != kCVReturnSuccess) { |
76 | av_log(NULL, AV_LOG_ERROR, "Error locking the pixel buffer.\n"); |
77 | return AVERROR_UNKNOWN; |
78 | } |
79 | |
80 | if (CVPixelBufferIsPlanar(pixbuf)) { |
81 | |
82 | planes = CVPixelBufferGetPlaneCount(pixbuf); |
83 | for (i = 0; i < planes; i++) { |
84 | data[i] = CVPixelBufferGetBaseAddressOfPlane(pixbuf, i); |
85 | linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf, i); |
86 | } |
87 | } else { |
88 | data[0] = CVPixelBufferGetBaseAddress(pixbuf); |
89 | linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf); |
90 | } |
91 | |
92 | av_image_copy(vt->tmp_frame->data, vt->tmp_frame->linesize, |
93 | (const uint8_t **)data, linesize, vt->tmp_frame->format, |
94 | frame->width, frame->height); |
95 | |
96 | ret = av_frame_copy_props(vt->tmp_frame, frame); |
97 | CVPixelBufferUnlockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly); |
98 | if (ret < 0) |
99 | return ret; |
100 | |
101 | av_frame_unref(frame); |
102 | av_frame_move_ref(frame, vt->tmp_frame); |
103 | |
104 | return 0; |
105 | } |
106 | |
107 | static void videotoolbox_uninit(AVCodecContext *s) |
108 | { |
109 | InputStream *ist = s->opaque; |
110 | VTContext *vt = ist->hwaccel_ctx; |
111 | |
112 | ist->hwaccel_uninit = NULL; |
113 | ist->hwaccel_retrieve_data = NULL; |
114 | |
115 | av_frame_free(&vt->tmp_frame); |
116 | |
117 | if (ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX) { |
118 | #if CONFIG_VIDEOTOOLBOX |
119 | av_videotoolbox_default_free(s); |
120 | #endif |
121 | } else { |
122 | #if CONFIG_VDA |
123 | av_vda_default_free(s); |
124 | #endif |
125 | } |
126 | av_freep(&ist->hwaccel_ctx); |
127 | } |
128 | |
129 | int videotoolbox_init(AVCodecContext *s) |
130 | { |
131 | InputStream *ist = s->opaque; |
132 | int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; |
133 | int ret = 0; |
134 | VTContext *vt; |
135 | |
136 | vt = av_mallocz(sizeof(*vt)); |
137 | if (!vt) |
138 | return AVERROR(ENOMEM); |
139 | |
140 | ist->hwaccel_ctx = vt; |
141 | ist->hwaccel_uninit = videotoolbox_uninit; |
142 | ist->hwaccel_retrieve_data = videotoolbox_retrieve_data; |
143 | |
144 | vt->tmp_frame = av_frame_alloc(); |
145 | if (!vt->tmp_frame) { |
146 | ret = AVERROR(ENOMEM); |
147 | goto fail; |
148 | } |
149 | |
150 | if (ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX) { |
151 | #if CONFIG_VIDEOTOOLBOX |
152 | if (!videotoolbox_pixfmt) { |
153 | ret = av_videotoolbox_default_init(s); |
154 | } else { |
155 | AVVideotoolboxContext *vtctx = av_videotoolbox_alloc_context(); |
156 | CFStringRef pixfmt_str = CFStringCreateWithCString(kCFAllocatorDefault, |
157 | videotoolbox_pixfmt, |
158 | kCFStringEncodingUTF8); |
159 | #if HAVE_UTGETOSTYPEFROMSTRING |
160 | vtctx->cv_pix_fmt_type = UTGetOSTypeFromString(pixfmt_str); |
161 | #else |
162 | av_log(s, loglevel, "UTGetOSTypeFromString() is not available " |
163 | "on this platform, %s pixel format can not be honored from " |
164 | "the command line\n", videotoolbox_pixfmt); |
165 | #endif |
166 | ret = av_videotoolbox_default_init2(s, vtctx); |
167 | CFRelease(pixfmt_str); |
168 | } |
169 | #endif |
170 | } else { |
171 | #if CONFIG_VDA |
172 | if (!videotoolbox_pixfmt) { |
173 | ret = av_vda_default_init(s); |
174 | } else { |
175 | AVVDAContext *vdactx = av_vda_alloc_context(); |
176 | CFStringRef pixfmt_str = CFStringCreateWithCString(kCFAllocatorDefault, |
177 | videotoolbox_pixfmt, |
178 | kCFStringEncodingUTF8); |
179 | #if HAVE_UTGETOSTYPEFROMSTRING |
180 | vdactx->cv_pix_fmt_type = UTGetOSTypeFromString(pixfmt_str); |
181 | #else |
182 | av_log(s, loglevel, "UTGetOSTypeFromString() is not available " |
183 | "on this platform, %s pixel format can not be honored from " |
184 | "the command line\n", videotoolbox_pixfmt); |
185 | #endif |
186 | ret = av_vda_default_init2(s, vdactx); |
187 | CFRelease(pixfmt_str); |
188 | } |
189 | #endif |
190 | } |
191 | if (ret < 0) { |
192 | av_log(NULL, loglevel, |
193 | "Error creating %s decoder.\n", ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX ? "Videotoolbox" : "VDA"); |
194 | goto fail; |
195 | } |
196 | |
197 | return 0; |
198 | fail: |
199 | videotoolbox_uninit(s); |
200 | return ret; |
201 | } |
202 |