/src/ffmpeg/libavutil/frame.c
Line | Count | Source |
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 "channel_layout.h" |
20 | | #include "avassert.h" |
21 | | #include "buffer.h" |
22 | | #include "dict.h" |
23 | | #include "frame.h" |
24 | | #include "frame_internal.h" |
25 | | #include "imgutils.h" |
26 | | #include "mem.h" |
27 | | #include "refstruct.h" |
28 | | #include "samplefmt.h" |
29 | | #include "side_data.h" |
30 | | #include "hwcontext.h" |
31 | | |
32 | | static void get_frame_defaults(AVFrame *frame) |
33 | 0 | { |
34 | 0 | memset(frame, 0, sizeof(*frame)); |
35 | |
|
36 | 0 | frame->pts = |
37 | 0 | frame->pkt_dts = AV_NOPTS_VALUE; |
38 | 0 | frame->best_effort_timestamp = AV_NOPTS_VALUE; |
39 | 0 | frame->duration = 0; |
40 | 0 | frame->time_base = (AVRational){ 0, 1 }; |
41 | 0 | frame->sample_aspect_ratio = (AVRational){ 0, 1 }; |
42 | 0 | frame->format = -1; /* unknown */ |
43 | 0 | frame->extended_data = frame->data; |
44 | 0 | frame->color_primaries = AVCOL_PRI_UNSPECIFIED; |
45 | 0 | frame->color_trc = AVCOL_TRC_UNSPECIFIED; |
46 | 0 | frame->colorspace = AVCOL_SPC_UNSPECIFIED; |
47 | 0 | frame->color_range = AVCOL_RANGE_UNSPECIFIED; |
48 | 0 | frame->chroma_location = AVCHROMA_LOC_UNSPECIFIED; |
49 | 0 | frame->alpha_mode = AVALPHA_MODE_UNSPECIFIED; |
50 | 0 | frame->flags = 0; |
51 | 0 | } |
52 | | |
53 | | AVFrame *av_frame_alloc(void) |
54 | 0 | { |
55 | 0 | AVFrame *frame = av_malloc(sizeof(*frame)); |
56 | |
|
57 | 0 | if (!frame) |
58 | 0 | return NULL; |
59 | | |
60 | 0 | get_frame_defaults(frame); |
61 | |
|
62 | 0 | return frame; |
63 | 0 | } |
64 | | |
65 | | void av_frame_free(AVFrame **frame) |
66 | 0 | { |
67 | 0 | if (!frame || !*frame) |
68 | 0 | return; |
69 | | |
70 | 0 | av_frame_unref(*frame); |
71 | 0 | av_freep(frame); |
72 | 0 | } |
73 | | |
74 | 0 | #define ALIGN (HAVE_SIMD_ALIGN_64 ? 64 : 32) |
75 | | |
76 | | int ff_frame_get_video_buffer(AVFrame *frame, int align, |
77 | | AVBufferRef *(*alloc)(void *opaque, size_t size), |
78 | | void *opaque) |
79 | 0 | { |
80 | 0 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); |
81 | 0 | int ret, padded_height; |
82 | 0 | int plane_padding; |
83 | 0 | ptrdiff_t linesizes[4]; |
84 | 0 | size_t total_size, sizes[4]; |
85 | |
|
86 | 0 | if (!desc) |
87 | 0 | return AVERROR(EINVAL); |
88 | | |
89 | 0 | if ((ret = av_image_check_size(frame->width, frame->height, 0, NULL)) < 0) |
90 | 0 | return ret; |
91 | | |
92 | 0 | if (align <= 0) |
93 | 0 | align = ALIGN; |
94 | 0 | plane_padding = FFMAX(ALIGN, align); |
95 | |
|
96 | 0 | if (!frame->linesize[0]) { |
97 | 0 | for (int i = 1; i <= align; i += i) { |
98 | 0 | ret = av_image_fill_linesizes(frame->linesize, frame->format, |
99 | 0 | FFALIGN(frame->width, i)); |
100 | 0 | if (ret < 0) |
101 | 0 | return ret; |
102 | 0 | if (!(frame->linesize[0] & (align-1))) |
103 | 0 | break; |
104 | 0 | } |
105 | | |
106 | 0 | for (int i = 0; i < 4 && frame->linesize[i]; i++) |
107 | 0 | frame->linesize[i] = FFALIGN(frame->linesize[i], align); |
108 | 0 | } |
109 | | |
110 | 0 | for (int i = 0; i < 4; i++) |
111 | 0 | linesizes[i] = frame->linesize[i]; |
112 | |
|
113 | 0 | padded_height = FFALIGN(frame->height, 32); |
114 | 0 | if ((ret = av_image_fill_plane_sizes(sizes, frame->format, |
115 | 0 | padded_height, linesizes)) < 0) |
116 | 0 | return ret; |
117 | | |
118 | 0 | total_size = 4 * plane_padding + 4 * align; |
119 | 0 | for (int i = 0; i < 4; i++) { |
120 | 0 | if (sizes[i] > SIZE_MAX - total_size) |
121 | 0 | return AVERROR(EINVAL); |
122 | 0 | total_size += sizes[i]; |
123 | 0 | } |
124 | | |
125 | 0 | frame->buf[0] = alloc ? alloc(opaque, total_size) : av_buffer_alloc(total_size); |
126 | 0 | if (!frame->buf[0]) { |
127 | 0 | ret = AVERROR(ENOMEM); |
128 | 0 | goto fail; |
129 | 0 | } |
130 | | |
131 | 0 | if ((ret = av_image_fill_pointers(frame->data, frame->format, padded_height, |
132 | 0 | frame->buf[0]->data, frame->linesize)) < 0) |
133 | 0 | goto fail; |
134 | | |
135 | 0 | for (int i = 1; i < 4; i++) { |
136 | 0 | if (frame->data[i]) |
137 | 0 | frame->data[i] += i * plane_padding; |
138 | 0 | frame->data[i] = (uint8_t *)FFALIGN((uintptr_t)frame->data[i], align); |
139 | 0 | } |
140 | |
|
141 | 0 | frame->extended_data = frame->data; |
142 | |
|
143 | 0 | return 0; |
144 | 0 | fail: |
145 | 0 | av_frame_unref(frame); |
146 | 0 | return ret; |
147 | 0 | } |
148 | | |
149 | | static int get_audio_buffer(AVFrame *frame, int align) |
150 | 0 | { |
151 | 0 | int planar = av_sample_fmt_is_planar(frame->format); |
152 | 0 | int channels, planes; |
153 | 0 | size_t size; |
154 | 0 | int ret; |
155 | |
|
156 | 0 | channels = frame->ch_layout.nb_channels; |
157 | 0 | planes = planar ? channels : 1; |
158 | 0 | if (!frame->linesize[0]) { |
159 | 0 | ret = av_samples_get_buffer_size(&frame->linesize[0], channels, |
160 | 0 | frame->nb_samples, frame->format, |
161 | 0 | align); |
162 | 0 | if (ret < 0) |
163 | 0 | return ret; |
164 | 0 | } |
165 | | |
166 | 0 | if (align <= 0) |
167 | 0 | align = ALIGN; |
168 | |
|
169 | 0 | if (planes > AV_NUM_DATA_POINTERS) { |
170 | 0 | frame->extended_data = av_calloc(planes, |
171 | 0 | sizeof(*frame->extended_data)); |
172 | 0 | frame->extended_buf = av_calloc(planes - AV_NUM_DATA_POINTERS, |
173 | 0 | sizeof(*frame->extended_buf)); |
174 | 0 | if (!frame->extended_data || !frame->extended_buf) { |
175 | 0 | av_freep(&frame->extended_data); |
176 | 0 | av_freep(&frame->extended_buf); |
177 | 0 | return AVERROR(ENOMEM); |
178 | 0 | } |
179 | 0 | frame->nb_extended_buf = planes - AV_NUM_DATA_POINTERS; |
180 | 0 | } else |
181 | 0 | frame->extended_data = frame->data; |
182 | | |
183 | 0 | if (frame->linesize[0] > SIZE_MAX - align) |
184 | 0 | return AVERROR(EINVAL); |
185 | 0 | size = frame->linesize[0] + (size_t)align; |
186 | |
|
187 | 0 | for (int i = 0; i < FFMIN(planes, AV_NUM_DATA_POINTERS); i++) { |
188 | 0 | frame->buf[i] = av_buffer_alloc(size); |
189 | 0 | if (!frame->buf[i]) { |
190 | 0 | av_frame_unref(frame); |
191 | 0 | return AVERROR(ENOMEM); |
192 | 0 | } |
193 | 0 | frame->extended_data[i] = frame->data[i] = |
194 | 0 | (uint8_t *)FFALIGN((uintptr_t)frame->buf[i]->data, align); |
195 | 0 | } |
196 | 0 | for (int i = 0; i < planes - AV_NUM_DATA_POINTERS; i++) { |
197 | 0 | frame->extended_buf[i] = av_buffer_alloc(size); |
198 | 0 | if (!frame->extended_buf[i]) { |
199 | 0 | av_frame_unref(frame); |
200 | 0 | return AVERROR(ENOMEM); |
201 | 0 | } |
202 | 0 | frame->extended_data[i + AV_NUM_DATA_POINTERS] = |
203 | 0 | (uint8_t *)FFALIGN((uintptr_t)frame->extended_buf[i]->data, align); |
204 | 0 | } |
205 | 0 | return 0; |
206 | |
|
207 | 0 | } |
208 | | |
209 | | int av_frame_get_buffer(AVFrame *frame, int align) |
210 | 0 | { |
211 | 0 | if (frame->format < 0) |
212 | 0 | return AVERROR(EINVAL); |
213 | | |
214 | 0 | if (frame->width > 0 && frame->height > 0) |
215 | 0 | return ff_frame_get_video_buffer(frame, align, NULL, NULL); |
216 | 0 | else if (frame->nb_samples > 0 && |
217 | 0 | (av_channel_layout_check(&frame->ch_layout))) |
218 | 0 | return get_audio_buffer(frame, align); |
219 | | |
220 | 0 | return AVERROR(EINVAL); |
221 | 0 | } |
222 | | |
223 | | static int frame_copy_props(AVFrame *dst, const AVFrame *src, int force_copy) |
224 | 0 | { |
225 | 0 | dst->pict_type = src->pict_type; |
226 | 0 | dst->sample_aspect_ratio = src->sample_aspect_ratio; |
227 | 0 | dst->crop_top = src->crop_top; |
228 | 0 | dst->crop_bottom = src->crop_bottom; |
229 | 0 | dst->crop_left = src->crop_left; |
230 | 0 | dst->crop_right = src->crop_right; |
231 | 0 | dst->pts = src->pts; |
232 | 0 | dst->duration = src->duration; |
233 | 0 | dst->repeat_pict = src->repeat_pict; |
234 | 0 | dst->sample_rate = src->sample_rate; |
235 | 0 | dst->opaque = src->opaque; |
236 | 0 | dst->pkt_dts = src->pkt_dts; |
237 | 0 | dst->time_base = src->time_base; |
238 | 0 | dst->quality = src->quality; |
239 | 0 | dst->best_effort_timestamp = src->best_effort_timestamp; |
240 | 0 | dst->flags = src->flags; |
241 | 0 | dst->decode_error_flags = src->decode_error_flags; |
242 | 0 | dst->color_primaries = src->color_primaries; |
243 | 0 | dst->color_trc = src->color_trc; |
244 | 0 | dst->colorspace = src->colorspace; |
245 | 0 | dst->color_range = src->color_range; |
246 | 0 | dst->chroma_location = src->chroma_location; |
247 | 0 | dst->alpha_mode = src->alpha_mode; |
248 | |
|
249 | 0 | av_dict_copy(&dst->metadata, src->metadata, 0); |
250 | |
|
251 | 0 | for (int i = 0; i < src->nb_side_data; i++) { |
252 | 0 | const AVFrameSideData *sd_src = src->side_data[i]; |
253 | 0 | AVFrameSideData *sd_dst; |
254 | 0 | if ( sd_src->type == AV_FRAME_DATA_PANSCAN |
255 | 0 | && (src->width != dst->width || src->height != dst->height)) |
256 | 0 | continue; |
257 | 0 | if (force_copy) { |
258 | 0 | sd_dst = av_frame_new_side_data(dst, sd_src->type, |
259 | 0 | sd_src->size); |
260 | 0 | if (!sd_dst) { |
261 | 0 | av_frame_side_data_free(&dst->side_data, &dst->nb_side_data); |
262 | 0 | return AVERROR(ENOMEM); |
263 | 0 | } |
264 | 0 | memcpy(sd_dst->data, sd_src->data, sd_src->size); |
265 | 0 | } else { |
266 | 0 | AVBufferRef *ref = av_buffer_ref(sd_src->buf); |
267 | 0 | sd_dst = av_frame_new_side_data_from_buf(dst, sd_src->type, ref); |
268 | 0 | if (!sd_dst) { |
269 | 0 | av_buffer_unref(&ref); |
270 | 0 | av_frame_side_data_free(&dst->side_data, &dst->nb_side_data); |
271 | 0 | return AVERROR(ENOMEM); |
272 | 0 | } |
273 | 0 | } |
274 | 0 | av_dict_copy(&sd_dst->metadata, sd_src->metadata, 0); |
275 | 0 | } |
276 | | |
277 | 0 | av_refstruct_replace(&dst->private_ref, src->private_ref); |
278 | 0 | return av_buffer_replace(&dst->opaque_ref, src->opaque_ref); |
279 | 0 | } |
280 | | |
281 | | int av_frame_ref(AVFrame *dst, const AVFrame *src) |
282 | 0 | { |
283 | 0 | int ret = 0; |
284 | |
|
285 | 0 | av_assert1(dst->width == 0 && dst->height == 0); |
286 | 0 | av_assert1(dst->ch_layout.nb_channels == 0 && |
287 | 0 | dst->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC); |
288 | |
|
289 | 0 | dst->format = src->format; |
290 | 0 | dst->width = src->width; |
291 | 0 | dst->height = src->height; |
292 | 0 | dst->nb_samples = src->nb_samples; |
293 | |
|
294 | 0 | ret = frame_copy_props(dst, src, 0); |
295 | 0 | if (ret < 0) |
296 | 0 | goto fail; |
297 | | |
298 | 0 | ret = av_channel_layout_copy(&dst->ch_layout, &src->ch_layout); |
299 | 0 | if (ret < 0) |
300 | 0 | goto fail; |
301 | | |
302 | | /* duplicate the frame data if it's not refcounted */ |
303 | 0 | if (!src->buf[0]) { |
304 | 0 | ret = av_frame_get_buffer(dst, 0); |
305 | 0 | if (ret < 0) |
306 | 0 | goto fail; |
307 | | |
308 | 0 | ret = av_frame_copy(dst, src); |
309 | 0 | if (ret < 0) |
310 | 0 | goto fail; |
311 | | |
312 | 0 | return 0; |
313 | 0 | } |
314 | | |
315 | | /* ref the buffers */ |
316 | 0 | for (int i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) { |
317 | 0 | if (!src->buf[i]) |
318 | 0 | continue; |
319 | 0 | dst->buf[i] = av_buffer_ref(src->buf[i]); |
320 | 0 | if (!dst->buf[i]) { |
321 | 0 | ret = AVERROR(ENOMEM); |
322 | 0 | goto fail; |
323 | 0 | } |
324 | 0 | } |
325 | | |
326 | 0 | if (src->extended_buf) { |
327 | 0 | dst->extended_buf = av_calloc(src->nb_extended_buf, |
328 | 0 | sizeof(*dst->extended_buf)); |
329 | 0 | if (!dst->extended_buf) { |
330 | 0 | ret = AVERROR(ENOMEM); |
331 | 0 | goto fail; |
332 | 0 | } |
333 | 0 | dst->nb_extended_buf = src->nb_extended_buf; |
334 | |
|
335 | 0 | for (int i = 0; i < src->nb_extended_buf; i++) { |
336 | 0 | dst->extended_buf[i] = av_buffer_ref(src->extended_buf[i]); |
337 | 0 | if (!dst->extended_buf[i]) { |
338 | 0 | ret = AVERROR(ENOMEM); |
339 | 0 | goto fail; |
340 | 0 | } |
341 | 0 | } |
342 | 0 | } |
343 | | |
344 | 0 | if (src->hw_frames_ctx) { |
345 | 0 | dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx); |
346 | 0 | if (!dst->hw_frames_ctx) { |
347 | 0 | ret = AVERROR(ENOMEM); |
348 | 0 | goto fail; |
349 | 0 | } |
350 | 0 | } |
351 | | |
352 | | /* duplicate extended data */ |
353 | 0 | if (src->extended_data != src->data) { |
354 | 0 | int ch = dst->ch_layout.nb_channels; |
355 | |
|
356 | 0 | if (ch <= 0 || ch > SIZE_MAX / sizeof(*dst->extended_data)) { |
357 | 0 | ret = AVERROR(EINVAL); |
358 | 0 | goto fail; |
359 | 0 | } |
360 | | |
361 | 0 | dst->extended_data = av_memdup(src->extended_data, sizeof(*dst->extended_data) * ch); |
362 | 0 | if (!dst->extended_data) { |
363 | 0 | ret = AVERROR(ENOMEM); |
364 | 0 | goto fail; |
365 | 0 | } |
366 | 0 | } else |
367 | 0 | dst->extended_data = dst->data; |
368 | | |
369 | 0 | memcpy(dst->data, src->data, sizeof(src->data)); |
370 | 0 | memcpy(dst->linesize, src->linesize, sizeof(src->linesize)); |
371 | |
|
372 | 0 | return 0; |
373 | | |
374 | 0 | fail: |
375 | 0 | av_frame_unref(dst); |
376 | 0 | return ret; |
377 | 0 | } |
378 | | |
379 | | int av_frame_replace(AVFrame *dst, const AVFrame *src) |
380 | 0 | { |
381 | 0 | int ret = 0; |
382 | |
|
383 | 0 | if (dst == src) |
384 | 0 | return AVERROR(EINVAL); |
385 | | |
386 | 0 | if (!src->buf[0]) { |
387 | 0 | av_frame_unref(dst); |
388 | | |
389 | | /* duplicate the frame data if it's not refcounted */ |
390 | 0 | if ( src->data[0] || src->data[1] |
391 | 0 | || src->data[2] || src->data[3]) |
392 | 0 | return av_frame_ref(dst, src); |
393 | | |
394 | 0 | ret = frame_copy_props(dst, src, 0); |
395 | 0 | if (ret < 0) |
396 | 0 | goto fail; |
397 | 0 | } |
398 | | |
399 | 0 | dst->format = src->format; |
400 | 0 | dst->width = src->width; |
401 | 0 | dst->height = src->height; |
402 | 0 | dst->nb_samples = src->nb_samples; |
403 | |
|
404 | 0 | ret = av_channel_layout_copy(&dst->ch_layout, &src->ch_layout); |
405 | 0 | if (ret < 0) |
406 | 0 | goto fail; |
407 | | |
408 | 0 | av_frame_side_data_free(&dst->side_data, &dst->nb_side_data); |
409 | 0 | av_dict_free(&dst->metadata); |
410 | 0 | ret = frame_copy_props(dst, src, 0); |
411 | 0 | if (ret < 0) |
412 | 0 | goto fail; |
413 | | |
414 | | /* replace the buffers */ |
415 | 0 | for (int i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) { |
416 | 0 | ret = av_buffer_replace(&dst->buf[i], src->buf[i]); |
417 | 0 | if (ret < 0) |
418 | 0 | goto fail; |
419 | 0 | } |
420 | | |
421 | 0 | if (src->extended_buf) { |
422 | 0 | if (dst->nb_extended_buf != src->nb_extended_buf) { |
423 | 0 | int nb_extended_buf = FFMIN(dst->nb_extended_buf, src->nb_extended_buf); |
424 | 0 | void *tmp; |
425 | |
|
426 | 0 | for (int i = nb_extended_buf; i < dst->nb_extended_buf; i++) |
427 | 0 | av_buffer_unref(&dst->extended_buf[i]); |
428 | |
|
429 | 0 | tmp = av_realloc_array(dst->extended_buf, src->nb_extended_buf, |
430 | 0 | sizeof(*dst->extended_buf)); |
431 | 0 | if (!tmp) { |
432 | 0 | ret = AVERROR(ENOMEM); |
433 | 0 | goto fail; |
434 | 0 | } |
435 | 0 | dst->extended_buf = tmp; |
436 | 0 | dst->nb_extended_buf = src->nb_extended_buf; |
437 | |
|
438 | 0 | memset(&dst->extended_buf[nb_extended_buf], 0, |
439 | 0 | (src->nb_extended_buf - nb_extended_buf) * sizeof(*dst->extended_buf)); |
440 | 0 | } |
441 | | |
442 | 0 | for (int i = 0; i < src->nb_extended_buf; i++) { |
443 | 0 | ret = av_buffer_replace(&dst->extended_buf[i], src->extended_buf[i]); |
444 | 0 | if (ret < 0) |
445 | 0 | goto fail; |
446 | 0 | } |
447 | 0 | } else if (dst->extended_buf) { |
448 | 0 | for (int i = 0; i < dst->nb_extended_buf; i++) |
449 | 0 | av_buffer_unref(&dst->extended_buf[i]); |
450 | 0 | av_freep(&dst->extended_buf); |
451 | 0 | } |
452 | | |
453 | 0 | ret = av_buffer_replace(&dst->hw_frames_ctx, src->hw_frames_ctx); |
454 | 0 | if (ret < 0) |
455 | 0 | goto fail; |
456 | | |
457 | 0 | if (dst->extended_data != dst->data) |
458 | 0 | av_freep(&dst->extended_data); |
459 | |
|
460 | 0 | if (src->extended_data != src->data) { |
461 | 0 | int ch = dst->ch_layout.nb_channels; |
462 | |
|
463 | 0 | if (ch <= 0 || ch > SIZE_MAX / sizeof(*dst->extended_data)) { |
464 | 0 | ret = AVERROR(EINVAL); |
465 | 0 | goto fail; |
466 | 0 | } |
467 | | |
468 | 0 | dst->extended_data = av_memdup(src->extended_data, sizeof(*dst->extended_data) * ch); |
469 | 0 | if (!dst->extended_data) { |
470 | 0 | ret = AVERROR(ENOMEM); |
471 | 0 | goto fail; |
472 | 0 | } |
473 | 0 | } else |
474 | 0 | dst->extended_data = dst->data; |
475 | | |
476 | 0 | memcpy(dst->data, src->data, sizeof(src->data)); |
477 | 0 | memcpy(dst->linesize, src->linesize, sizeof(src->linesize)); |
478 | |
|
479 | 0 | return 0; |
480 | | |
481 | 0 | fail: |
482 | 0 | av_frame_unref(dst); |
483 | 0 | return ret; |
484 | 0 | } |
485 | | |
486 | | AVFrame *av_frame_clone(const AVFrame *src) |
487 | 0 | { |
488 | 0 | AVFrame *ret = av_frame_alloc(); |
489 | |
|
490 | 0 | if (!ret) |
491 | 0 | return NULL; |
492 | | |
493 | 0 | if (av_frame_ref(ret, src) < 0) |
494 | 0 | av_frame_free(&ret); |
495 | |
|
496 | 0 | return ret; |
497 | 0 | } |
498 | | |
499 | | void av_frame_unref(AVFrame *frame) |
500 | 0 | { |
501 | 0 | if (!frame) |
502 | 0 | return; |
503 | | |
504 | 0 | av_frame_side_data_free(&frame->side_data, &frame->nb_side_data); |
505 | |
|
506 | 0 | for (int i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++) |
507 | 0 | av_buffer_unref(&frame->buf[i]); |
508 | 0 | for (int i = 0; i < frame->nb_extended_buf; i++) |
509 | 0 | av_buffer_unref(&frame->extended_buf[i]); |
510 | 0 | av_freep(&frame->extended_buf); |
511 | 0 | av_dict_free(&frame->metadata); |
512 | |
|
513 | 0 | av_buffer_unref(&frame->hw_frames_ctx); |
514 | |
|
515 | 0 | av_buffer_unref(&frame->opaque_ref); |
516 | 0 | av_refstruct_unref(&frame->private_ref); |
517 | |
|
518 | 0 | if (frame->extended_data != frame->data) |
519 | 0 | av_freep(&frame->extended_data); |
520 | |
|
521 | 0 | av_channel_layout_uninit(&frame->ch_layout); |
522 | |
|
523 | 0 | get_frame_defaults(frame); |
524 | 0 | } |
525 | | |
526 | | void av_frame_move_ref(AVFrame *dst, AVFrame *src) |
527 | 0 | { |
528 | 0 | av_assert1(dst->width == 0 && dst->height == 0); |
529 | 0 | av_assert1(dst->ch_layout.nb_channels == 0 && |
530 | 0 | dst->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC); |
531 | |
|
532 | 0 | *dst = *src; |
533 | 0 | if (src->extended_data == src->data) |
534 | 0 | dst->extended_data = dst->data; |
535 | 0 | get_frame_defaults(src); |
536 | 0 | } |
537 | | |
538 | | int av_frame_is_writable(AVFrame *frame) |
539 | 0 | { |
540 | 0 | int ret = 1; |
541 | | |
542 | | /* assume non-refcounted frames are not writable */ |
543 | 0 | if (!frame->buf[0]) |
544 | 0 | return 0; |
545 | | |
546 | 0 | for (int i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++) |
547 | 0 | if (frame->buf[i]) |
548 | 0 | ret &= !!av_buffer_is_writable(frame->buf[i]); |
549 | 0 | for (int i = 0; i < frame->nb_extended_buf; i++) |
550 | 0 | ret &= !!av_buffer_is_writable(frame->extended_buf[i]); |
551 | |
|
552 | 0 | return ret; |
553 | 0 | } |
554 | | |
555 | | int av_frame_make_writable(AVFrame *frame) |
556 | 0 | { |
557 | 0 | AVFrame tmp; |
558 | 0 | int ret; |
559 | |
|
560 | 0 | if (av_frame_is_writable(frame)) |
561 | 0 | return 0; |
562 | | |
563 | 0 | memset(&tmp, 0, sizeof(tmp)); |
564 | 0 | tmp.format = frame->format; |
565 | 0 | tmp.width = frame->width; |
566 | 0 | tmp.height = frame->height; |
567 | 0 | tmp.nb_samples = frame->nb_samples; |
568 | 0 | ret = av_channel_layout_copy(&tmp.ch_layout, &frame->ch_layout); |
569 | 0 | if (ret < 0) { |
570 | 0 | av_frame_unref(&tmp); |
571 | 0 | return ret; |
572 | 0 | } |
573 | | |
574 | 0 | if (frame->hw_frames_ctx) |
575 | 0 | ret = av_hwframe_get_buffer(frame->hw_frames_ctx, &tmp, 0); |
576 | 0 | else |
577 | 0 | ret = av_frame_get_buffer(&tmp, 0); |
578 | 0 | if (ret < 0) |
579 | 0 | return ret; |
580 | | |
581 | 0 | ret = av_frame_copy(&tmp, frame); |
582 | 0 | if (ret < 0) { |
583 | 0 | av_frame_unref(&tmp); |
584 | 0 | return ret; |
585 | 0 | } |
586 | | |
587 | 0 | ret = av_frame_copy_props(&tmp, frame); |
588 | 0 | if (ret < 0) { |
589 | 0 | av_frame_unref(&tmp); |
590 | 0 | return ret; |
591 | 0 | } |
592 | | |
593 | 0 | av_frame_unref(frame); |
594 | |
|
595 | 0 | *frame = tmp; |
596 | 0 | if (tmp.data == tmp.extended_data) |
597 | 0 | frame->extended_data = frame->data; |
598 | |
|
599 | 0 | return 0; |
600 | 0 | } |
601 | | |
602 | | int av_frame_copy_props(AVFrame *dst, const AVFrame *src) |
603 | 0 | { |
604 | 0 | return frame_copy_props(dst, src, 1); |
605 | 0 | } |
606 | | |
607 | | AVBufferRef *av_frame_get_plane_buffer(const AVFrame *frame, int plane) |
608 | 0 | { |
609 | 0 | uintptr_t data; |
610 | 0 | int planes; |
611 | |
|
612 | 0 | if (frame->nb_samples) { |
613 | 0 | int channels = frame->ch_layout.nb_channels; |
614 | 0 | if (!channels) |
615 | 0 | return NULL; |
616 | 0 | planes = av_sample_fmt_is_planar(frame->format) ? channels : 1; |
617 | 0 | } else |
618 | 0 | planes = 4; |
619 | | |
620 | 0 | if (plane < 0 || plane >= planes || !frame->extended_data[plane]) |
621 | 0 | return NULL; |
622 | 0 | data = (uintptr_t)frame->extended_data[plane]; |
623 | |
|
624 | 0 | for (int i = 0; i < FF_ARRAY_ELEMS(frame->buf) && frame->buf[i]; i++) { |
625 | 0 | AVBufferRef *buf = frame->buf[i]; |
626 | 0 | uintptr_t buf_begin = (uintptr_t)buf->data; |
627 | |
|
628 | 0 | if (data >= buf_begin && data < buf_begin + buf->size) |
629 | 0 | return buf; |
630 | 0 | } |
631 | 0 | for (int i = 0; i < frame->nb_extended_buf; i++) { |
632 | 0 | AVBufferRef *buf = frame->extended_buf[i]; |
633 | 0 | uintptr_t buf_begin = (uintptr_t)buf->data; |
634 | |
|
635 | 0 | if (data >= buf_begin && data < buf_begin + buf->size) |
636 | 0 | return buf; |
637 | 0 | } |
638 | 0 | return NULL; |
639 | 0 | } |
640 | | |
641 | | AVFrameSideData *av_frame_new_side_data_from_buf(AVFrame *frame, |
642 | | enum AVFrameSideDataType type, |
643 | | AVBufferRef *buf) |
644 | 0 | { |
645 | 0 | return |
646 | 0 | ff_frame_side_data_add_from_buf( |
647 | 0 | &frame->side_data, &frame->nb_side_data, type, buf); |
648 | 0 | } |
649 | | |
650 | | AVFrameSideData *av_frame_new_side_data(AVFrame *frame, |
651 | | enum AVFrameSideDataType type, |
652 | | size_t size) |
653 | 0 | { |
654 | 0 | AVFrameSideData *ret; |
655 | 0 | AVBufferRef *buf = av_buffer_alloc(size); |
656 | 0 | ret = av_frame_new_side_data_from_buf(frame, type, buf); |
657 | 0 | if (!ret) |
658 | 0 | av_buffer_unref(&buf); |
659 | 0 | return ret; |
660 | 0 | } |
661 | | |
662 | | AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, |
663 | | enum AVFrameSideDataType type) |
664 | 0 | { |
665 | 0 | return (AVFrameSideData *)av_frame_side_data_get( |
666 | 0 | frame->side_data, frame->nb_side_data, |
667 | 0 | type |
668 | 0 | ); |
669 | 0 | } |
670 | | |
671 | | static int frame_copy_video(AVFrame *dst, const AVFrame *src) |
672 | 0 | { |
673 | 0 | int planes; |
674 | |
|
675 | 0 | if (dst->width < src->width || |
676 | 0 | dst->height < src->height) |
677 | 0 | return AVERROR(EINVAL); |
678 | | |
679 | 0 | if (src->hw_frames_ctx || dst->hw_frames_ctx) |
680 | 0 | return av_hwframe_transfer_data(dst, src, 0); |
681 | | |
682 | 0 | planes = av_pix_fmt_count_planes(dst->format); |
683 | 0 | for (int i = 0; i < planes; i++) |
684 | 0 | if (!dst->data[i] || !src->data[i]) |
685 | 0 | return AVERROR(EINVAL); |
686 | | |
687 | 0 | av_image_copy2(dst->data, dst->linesize, |
688 | 0 | src->data, src->linesize, |
689 | 0 | dst->format, src->width, src->height); |
690 | |
|
691 | 0 | return 0; |
692 | 0 | } |
693 | | |
694 | | static int frame_copy_audio(AVFrame *dst, const AVFrame *src) |
695 | 0 | { |
696 | 0 | int planar = av_sample_fmt_is_planar(dst->format); |
697 | 0 | int channels = dst->ch_layout.nb_channels; |
698 | 0 | int planes = planar ? channels : 1; |
699 | |
|
700 | 0 | if (dst->nb_samples != src->nb_samples || |
701 | 0 | av_channel_layout_compare(&dst->ch_layout, &src->ch_layout)) |
702 | 0 | return AVERROR(EINVAL); |
703 | | |
704 | 0 | for (int i = 0; i < planes; i++) |
705 | 0 | if (!dst->extended_data[i] || !src->extended_data[i]) |
706 | 0 | return AVERROR(EINVAL); |
707 | | |
708 | 0 | av_samples_copy(dst->extended_data, src->extended_data, 0, 0, |
709 | 0 | dst->nb_samples, channels, dst->format); |
710 | |
|
711 | 0 | return 0; |
712 | 0 | } |
713 | | |
714 | | int av_frame_copy(AVFrame *dst, const AVFrame *src) |
715 | 0 | { |
716 | 0 | if (dst->format != src->format || dst->format < 0) |
717 | 0 | return AVERROR(EINVAL); |
718 | | |
719 | 0 | if (dst->width > 0 && dst->height > 0) |
720 | 0 | return frame_copy_video(dst, src); |
721 | 0 | else if (dst->nb_samples > 0 && |
722 | 0 | (av_channel_layout_check(&dst->ch_layout))) |
723 | 0 | return frame_copy_audio(dst, src); |
724 | | |
725 | 0 | return AVERROR(EINVAL); |
726 | 0 | } |
727 | | |
728 | | void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type) |
729 | 0 | { |
730 | 0 | av_frame_side_data_remove(&frame->side_data, &frame->nb_side_data, type); |
731 | 0 | } |
732 | | |
733 | | static int calc_cropping_offsets(size_t offsets[4], const AVFrame *frame, |
734 | | const AVPixFmtDescriptor *desc) |
735 | 0 | { |
736 | 0 | for (int i = 0; frame->data[i]; i++) { |
737 | 0 | const AVComponentDescriptor *comp = NULL; |
738 | 0 | int shift_x = (i == 1 || i == 2) ? desc->log2_chroma_w : 0; |
739 | 0 | int shift_y = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; |
740 | |
|
741 | 0 | if (desc->flags & AV_PIX_FMT_FLAG_PAL && i == 1) { |
742 | 0 | offsets[i] = 0; |
743 | 0 | break; |
744 | 0 | } |
745 | | |
746 | | /* find any component descriptor for this plane */ |
747 | 0 | for (int j = 0; j < desc->nb_components; j++) { |
748 | 0 | if (desc->comp[j].plane == i) { |
749 | 0 | comp = &desc->comp[j]; |
750 | 0 | break; |
751 | 0 | } |
752 | 0 | } |
753 | 0 | if (!comp) |
754 | 0 | return AVERROR_BUG; |
755 | | |
756 | 0 | offsets[i] = (frame->crop_top >> shift_y) * frame->linesize[i] + |
757 | 0 | (frame->crop_left >> shift_x) * comp->step; |
758 | 0 | } |
759 | | |
760 | 0 | return 0; |
761 | 0 | } |
762 | | |
763 | | int av_frame_apply_cropping(AVFrame *frame, int flags) |
764 | 0 | { |
765 | 0 | const AVPixFmtDescriptor *desc; |
766 | 0 | size_t offsets[4]; |
767 | 0 | int ret; |
768 | |
|
769 | 0 | if (!(frame->width > 0 && frame->height > 0)) |
770 | 0 | return AVERROR(EINVAL); |
771 | | |
772 | 0 | if (frame->crop_left >= INT_MAX - frame->crop_right || |
773 | 0 | frame->crop_top >= INT_MAX - frame->crop_bottom || |
774 | 0 | (frame->crop_left + frame->crop_right) >= frame->width || |
775 | 0 | (frame->crop_top + frame->crop_bottom) >= frame->height) |
776 | 0 | return AVERROR(ERANGE); |
777 | | |
778 | 0 | desc = av_pix_fmt_desc_get(frame->format); |
779 | 0 | if (!desc) |
780 | 0 | return AVERROR_BUG; |
781 | | |
782 | | /* Apply just the right/bottom cropping for hwaccel formats. Bitstream |
783 | | * formats cannot be easily handled here either (and corresponding decoders |
784 | | * should not export any cropping anyway), so do the same for those as well. |
785 | | * */ |
786 | 0 | if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_HWACCEL)) { |
787 | 0 | frame->width -= frame->crop_right; |
788 | 0 | frame->height -= frame->crop_bottom; |
789 | 0 | frame->crop_right = 0; |
790 | 0 | frame->crop_bottom = 0; |
791 | 0 | return 0; |
792 | 0 | } |
793 | | |
794 | | /* calculate the offsets for each plane */ |
795 | 0 | ret = calc_cropping_offsets(offsets, frame, desc); |
796 | 0 | if (ret < 0) |
797 | 0 | return ret; |
798 | | |
799 | | /* adjust the offsets to avoid breaking alignment */ |
800 | 0 | if (!(flags & AV_FRAME_CROP_UNALIGNED)) { |
801 | 0 | int log2_crop_align = frame->crop_left ? ff_ctz(frame->crop_left) : INT_MAX; |
802 | 0 | int min_log2_align = INT_MAX; |
803 | |
|
804 | 0 | for (int i = 0; frame->data[i]; i++) { |
805 | 0 | int log2_align = offsets[i] ? ff_ctz(offsets[i]) : INT_MAX; |
806 | 0 | min_log2_align = FFMIN(log2_align, min_log2_align); |
807 | 0 | } |
808 | | |
809 | | /* The data alignment is the cropping alignment scaled by a power of 2, |
810 | | * up for multi-byte pixels and down for subsampled planes */ |
811 | 0 | if (min_log2_align < 5 && log2_crop_align != INT_MAX) { |
812 | 0 | frame->crop_left &= ~((1 << (5 + log2_crop_align - min_log2_align)) - 1); |
813 | 0 | ret = calc_cropping_offsets(offsets, frame, desc); |
814 | 0 | if (ret < 0) |
815 | 0 | return ret; |
816 | 0 | } |
817 | 0 | } |
818 | | |
819 | 0 | for (int i = 0; frame->data[i]; i++) |
820 | 0 | frame->data[i] += offsets[i]; |
821 | |
|
822 | 0 | frame->width -= (frame->crop_left + frame->crop_right); |
823 | 0 | frame->height -= (frame->crop_top + frame->crop_bottom); |
824 | 0 | frame->crop_left = 0; |
825 | 0 | frame->crop_right = 0; |
826 | 0 | frame->crop_top = 0; |
827 | 0 | frame->crop_bottom = 0; |
828 | |
|
829 | 0 | return 0; |
830 | 0 | } |