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