1 /*
2 * This file is part of FFmpeg.
3 *
4 * Copyright (c) 2015 Matthieu Bouron <matthieu.bouron stupeflix.com>
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "framepool.h"
22 #include "libavutil/avassert.h"
23 #include "libavutil/avutil.h"
24 #include "libavutil/buffer.h"
25 #include "libavutil/frame.h"
26 #include "libavutil/imgutils.h"
27 #include "libavutil/mem.h"
28 #include "libavutil/pixfmt.h"
29
30 struct FFFramePool {
31
32 enum AVMediaType type;
33
34 /* video */
35 int width;
36 int height;
37
38 /* audio */
39 int planes;
40 int channels;
41 int nb_samples;
42
43 /* common */
44 int format;
45 int align;
46 int linesize[4];
47 AVBufferPool *pools[4];
48
49 };
50
ff_frame_pool_video_init(AVBufferRef * (* alloc)(size_t size),int width,int height,enum AVPixelFormat format,int align)51 FFFramePool *ff_frame_pool_video_init(AVBufferRef* (*alloc)(size_t size),
52 int width,
53 int height,
54 enum AVPixelFormat format,
55 int align)
56 {
57 int i, ret;
58 FFFramePool *pool;
59 ptrdiff_t linesizes[4];
60 size_t sizes[4];
61
62 pool = av_mallocz(sizeof(FFFramePool));
63 if (!pool)
64 return NULL;
65
66 pool->type = AVMEDIA_TYPE_VIDEO;
67 pool->width = width;
68 pool->height = height;
69 pool->format = format;
70 pool->align = align;
71
72 if ((ret = av_image_check_size2(width, height, INT64_MAX, format, 0, NULL)) < 0) {
73 goto fail;
74 }
75
76 if (!pool->linesize[0]) {
77 ret = av_image_fill_linesizes(pool->linesize, pool->format,
78 FFALIGN(pool->width, align));
79 if (ret < 0) {
80 goto fail;
81 }
82
83 for (i = 0; i < 4 && pool->linesize[i]; i++) {
84 pool->linesize[i] = FFALIGN(pool->linesize[i], pool->align);
85 if ((pool->linesize[i] & (pool->align - 1)))
86 goto fail;
87 }
88 }
89
90 for (i = 0; i < 4; i++)
91 linesizes[i] = pool->linesize[i];
92
93 if (av_image_fill_plane_sizes(sizes, pool->format,
94 pool->height,
95 linesizes) < 0) {
96 goto fail;
97 }
98
99 for (i = 0; i < 4 && sizes[i]; i++) {
100 if (sizes[i] > SIZE_MAX - align)
101 goto fail;
102 pool->pools[i] = av_buffer_pool_init(sizes[i] + align, alloc);
103 if (!pool->pools[i])
104 goto fail;
105 }
106
107 return pool;
108
109 fail:
110 ff_frame_pool_uninit(&pool);
111 return NULL;
112 }
113
ff_frame_pool_audio_init(AVBufferRef * (* alloc)(size_t size),int channels,int nb_samples,enum AVSampleFormat format,int align)114 FFFramePool *ff_frame_pool_audio_init(AVBufferRef* (*alloc)(size_t size),
115 int channels,
116 int nb_samples,
117 enum AVSampleFormat format,
118 int align)
119 {
120 int ret, planar;
121 FFFramePool *pool;
122
123 pool = av_mallocz(sizeof(FFFramePool));
124 if (!pool)
125 return NULL;
126
127 planar = av_sample_fmt_is_planar(format);
128
129 pool->type = AVMEDIA_TYPE_AUDIO;
130 pool->planes = planar ? channels : 1;
131 pool->channels = channels;
132 pool->nb_samples = nb_samples;
133 pool->format = format;
134 pool->align = align;
135
136 ret = av_samples_get_buffer_size(&pool->linesize[0], channels,
137 nb_samples, format, 0);
138 if (ret < 0)
139 goto fail;
140
141 pool->pools[0] = av_buffer_pool_init(pool->linesize[0], NULL);
142 if (!pool->pools[0])
143 goto fail;
144
145 return pool;
146
147 fail:
148 ff_frame_pool_uninit(&pool);
149 return NULL;
150 }
151
ff_frame_pool_get_video_config(FFFramePool * pool,int * width,int * height,enum AVPixelFormat * format,int * align)152 int ff_frame_pool_get_video_config(FFFramePool *pool,
153 int *width,
154 int *height,
155 enum AVPixelFormat *format,
156 int *align)
157 {
158 if (!pool)
159 return AVERROR(EINVAL);
160
161 av_assert0(pool->type == AVMEDIA_TYPE_VIDEO);
162
163 *width = pool->width;
164 *height = pool->height;
165 *format = pool->format;
166 *align = pool->align;
167
168 return 0;
169 }
170
ff_frame_pool_get_audio_config(FFFramePool * pool,int * channels,int * nb_samples,enum AVSampleFormat * format,int * align)171 int ff_frame_pool_get_audio_config(FFFramePool *pool,
172 int *channels,
173 int *nb_samples,
174 enum AVSampleFormat *format,
175 int *align)
176 {
177 if (!pool)
178 return AVERROR(EINVAL);
179
180 av_assert0(pool->type == AVMEDIA_TYPE_AUDIO);
181
182 *channels = pool->channels;
183 *nb_samples = pool->nb_samples;
184 *format = pool->format;
185 *align = pool->align;
186
187 return 0;
188 }
189
ff_frame_pool_get(FFFramePool * pool)190 AVFrame *ff_frame_pool_get(FFFramePool *pool)
191 {
192 int i;
193 AVFrame *frame;
194 const AVPixFmtDescriptor *desc;
195
196 frame = av_frame_alloc();
197 if (!frame) {
198 return NULL;
199 }
200
201 switch(pool->type) {
202 case AVMEDIA_TYPE_VIDEO:
203 desc = av_pix_fmt_desc_get(pool->format);
204 if (!desc) {
205 goto fail;
206 }
207
208 frame->width = pool->width;
209 frame->height = pool->height;
210 frame->format = pool->format;
211
212 for (i = 0; i < 4; i++) {
213 frame->linesize[i] = pool->linesize[i];
214 if (!pool->pools[i])
215 break;
216
217 frame->buf[i] = av_buffer_pool_get(pool->pools[i]);
218 if (!frame->buf[i])
219 goto fail;
220
221 frame->data[i] = frame->buf[i]->data;
222 }
223
224 if (desc->flags & AV_PIX_FMT_FLAG_PAL) {
225 enum AVPixelFormat format =
226 pool->format == AV_PIX_FMT_PAL8 ? AV_PIX_FMT_BGR8 : pool->format;
227
228 av_assert0(frame->data[1] != NULL);
229 if (avpriv_set_systematic_pal2((uint32_t *)frame->data[1], format) < 0)
230 goto fail;
231 }
232
233 frame->extended_data = frame->data;
234 break;
235 case AVMEDIA_TYPE_AUDIO:
236 frame->nb_samples = pool->nb_samples;
237 #if FF_API_OLD_CHANNEL_LAYOUT
238 FF_DISABLE_DEPRECATION_WARNINGS
239 frame->channels = pool->channels;
240 FF_ENABLE_DEPRECATION_WARNINGS
241 #endif
242 frame->ch_layout.nb_channels = pool->channels;
243 frame->format = pool->format;
244 frame->linesize[0] = pool->linesize[0];
245
246 if (pool->planes > AV_NUM_DATA_POINTERS) {
247 frame->extended_data = av_calloc(pool->planes,
248 sizeof(*frame->extended_data));
249 frame->nb_extended_buf = pool->planes - AV_NUM_DATA_POINTERS;
250 frame->extended_buf = av_calloc(frame->nb_extended_buf,
251 sizeof(*frame->extended_buf));
252 if (!frame->extended_data || !frame->extended_buf)
253 goto fail;
254 } else {
255 frame->extended_data = frame->data;
256 av_assert0(frame->nb_extended_buf == 0);
257 }
258
259 for (i = 0; i < FFMIN(pool->planes, AV_NUM_DATA_POINTERS); i++) {
260 frame->buf[i] = av_buffer_pool_get(pool->pools[0]);
261 if (!frame->buf[i])
262 goto fail;
263 frame->extended_data[i] = frame->data[i] = frame->buf[i]->data;
264 }
265 for (i = 0; i < frame->nb_extended_buf; i++) {
266 frame->extended_buf[i] = av_buffer_pool_get(pool->pools[0]);
267 if (!frame->extended_buf[i])
268 goto fail;
269 frame->extended_data[i + AV_NUM_DATA_POINTERS] = frame->extended_buf[i]->data;
270 }
271
272 break;
273 default:
274 av_assert0(0);
275 }
276
277 return frame;
278 fail:
279 av_frame_free(&frame);
280 return NULL;
281 }
282
ff_frame_pool_uninit(FFFramePool ** pool)283 void ff_frame_pool_uninit(FFFramePool **pool)
284 {
285 int i;
286
287 if (!pool || !*pool)
288 return;
289
290 for (i = 0; i < 4; i++) {
291 av_buffer_pool_uninit(&(*pool)->pools[i]);
292 }
293
294 av_freep(pool);
295 }
296