avpacket: Deprecate av_dup_packet
[libav.git] / libavcodec / avpacket.c
1 /*
2 * AVPacket functions for libavcodec
3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4 *
5 * This file is part of Libav.
6 *
7 * Libav is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * Libav is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <string.h>
23
24 #include "libavutil/avassert.h"
25 #include "libavutil/common.h"
26 #include "libavutil/internal.h"
27 #include "libavutil/mathematics.h"
28 #include "libavutil/mem.h"
29 #include "avcodec.h"
30
31 void av_init_packet(AVPacket *pkt)
32 {
33 pkt->pts = AV_NOPTS_VALUE;
34 pkt->dts = AV_NOPTS_VALUE;
35 pkt->pos = -1;
36 pkt->duration = 0;
37 #if FF_API_CONVERGENCE_DURATION
38 FF_DISABLE_DEPRECATION_WARNINGS
39 pkt->convergence_duration = 0;
40 FF_ENABLE_DEPRECATION_WARNINGS
41 #endif
42 pkt->flags = 0;
43 pkt->stream_index = 0;
44 pkt->buf = NULL;
45 pkt->side_data = NULL;
46 pkt->side_data_elems = 0;
47 }
48
49 static int packet_alloc(AVBufferRef **buf, int size)
50 {
51 int ret;
52 if ((unsigned)size >= (unsigned)size + AV_INPUT_BUFFER_PADDING_SIZE)
53 return AVERROR(EINVAL);
54
55 ret = av_buffer_realloc(buf, size + AV_INPUT_BUFFER_PADDING_SIZE);
56 if (ret < 0)
57 return ret;
58
59 memset((*buf)->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
60
61 return 0;
62 }
63
64 int av_new_packet(AVPacket *pkt, int size)
65 {
66 AVBufferRef *buf = NULL;
67 int ret = packet_alloc(&buf, size);
68 if (ret < 0)
69 return ret;
70
71 av_init_packet(pkt);
72 pkt->buf = buf;
73 pkt->data = buf->data;
74 pkt->size = size;
75
76 return 0;
77 }
78
79 void av_shrink_packet(AVPacket *pkt, int size)
80 {
81 if (pkt->size <= size)
82 return;
83 pkt->size = size;
84 memset(pkt->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
85 }
86
87 int av_grow_packet(AVPacket *pkt, int grow_by)
88 {
89 int new_size;
90 av_assert0((unsigned)pkt->size <= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE);
91 if (!pkt->size)
92 return av_new_packet(pkt, grow_by);
93 if ((unsigned)grow_by >
94 INT_MAX - (pkt->size + AV_INPUT_BUFFER_PADDING_SIZE))
95 return -1;
96
97 new_size = pkt->size + grow_by + AV_INPUT_BUFFER_PADDING_SIZE;
98 if (pkt->buf) {
99 int ret = av_buffer_realloc(&pkt->buf, new_size);
100 if (ret < 0)
101 return ret;
102 } else {
103 pkt->buf = av_buffer_alloc(new_size);
104 if (!pkt->buf)
105 return AVERROR(ENOMEM);
106 memcpy(pkt->buf->data, pkt->data, FFMIN(pkt->size, pkt->size + grow_by));
107 }
108 pkt->data = pkt->buf->data;
109 pkt->size += grow_by;
110 memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
111
112 return 0;
113 }
114
115 int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size)
116 {
117 if (size >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
118 return AVERROR(EINVAL);
119
120 pkt->buf = av_buffer_create(data, size + AV_INPUT_BUFFER_PADDING_SIZE,
121 av_buffer_default_free, NULL, 0);
122 if (!pkt->buf)
123 return AVERROR(ENOMEM);
124
125 pkt->data = data;
126 pkt->size = size;
127
128 return 0;
129 }
130
131 #if FF_API_AVPACKET_OLD_API
132 FF_DISABLE_DEPRECATION_WARNINGS
133 #define ALLOC_MALLOC(data, size) data = av_malloc(size)
134 #define ALLOC_BUF(data, size) \
135 do { \
136 av_buffer_realloc(&pkt->buf, size); \
137 data = pkt->buf ? pkt->buf->data : NULL; \
138 } while (0)
139
140 #define DUP_DATA(dst, src, size, padding, ALLOC) \
141 do { \
142 void *data; \
143 if (padding) { \
144 if ((unsigned)(size) > \
145 (unsigned)(size) + AV_INPUT_BUFFER_PADDING_SIZE) \
146 goto failed_alloc; \
147 ALLOC(data, size + AV_INPUT_BUFFER_PADDING_SIZE); \
148 } else { \
149 ALLOC(data, size); \
150 } \
151 if (!data) \
152 goto failed_alloc; \
153 memcpy(data, src, size); \
154 if (padding) \
155 memset((uint8_t *)data + size, 0, \
156 AV_INPUT_BUFFER_PADDING_SIZE); \
157 dst = data; \
158 } while (0)
159
160 int av_dup_packet(AVPacket *pkt)
161 {
162 AVPacket tmp_pkt;
163
164 if (!pkt->buf && pkt->data) {
165 tmp_pkt = *pkt;
166
167 pkt->data = NULL;
168 pkt->side_data = NULL;
169 DUP_DATA(pkt->data, tmp_pkt.data, pkt->size, 1, ALLOC_BUF);
170
171 if (pkt->side_data_elems) {
172 int i;
173
174 DUP_DATA(pkt->side_data, tmp_pkt.side_data,
175 pkt->side_data_elems * sizeof(*pkt->side_data), 0, ALLOC_MALLOC);
176 memset(pkt->side_data, 0,
177 pkt->side_data_elems * sizeof(*pkt->side_data));
178 for (i = 0; i < pkt->side_data_elems; i++) {
179 DUP_DATA(pkt->side_data[i].data, tmp_pkt.side_data[i].data,
180 tmp_pkt.side_data[i].size, 1, ALLOC_MALLOC);
181 pkt->side_data[i].size = tmp_pkt.side_data[i].size;
182 pkt->side_data[i].type = tmp_pkt.side_data[i].type;
183 }
184 }
185 }
186 return 0;
187
188 failed_alloc:
189 av_packet_unref(pkt);
190 return AVERROR(ENOMEM);
191 }
192 FF_ENABLE_DEPRECATION_WARNINGS
193 #endif
194
195 void av_packet_free_side_data(AVPacket *pkt)
196 {
197 int i;
198 for (i = 0; i < pkt->side_data_elems; i++)
199 av_free(pkt->side_data[i].data);
200 av_freep(&pkt->side_data);
201 pkt->side_data_elems = 0;
202 }
203
204 #if FF_API_AVPACKET_OLD_API
205 FF_DISABLE_DEPRECATION_WARNINGS
206 void av_free_packet(AVPacket *pkt)
207 {
208 if (pkt) {
209 if (pkt->buf)
210 av_buffer_unref(&pkt->buf);
211 pkt->data = NULL;
212 pkt->size = 0;
213
214 av_packet_free_side_data(pkt);
215 }
216 }
217 FF_ENABLE_DEPRECATION_WARNINGS
218 #endif
219
220 uint8_t *av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
221 int size)
222 {
223 int elems = pkt->side_data_elems;
224
225 if ((unsigned)elems + 1 > INT_MAX / sizeof(*pkt->side_data))
226 return NULL;
227 if ((unsigned)size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
228 return NULL;
229
230 pkt->side_data = av_realloc(pkt->side_data,
231 (elems + 1) * sizeof(*pkt->side_data));
232 if (!pkt->side_data)
233 return NULL;
234
235 pkt->side_data[elems].data = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
236 if (!pkt->side_data[elems].data)
237 return NULL;
238 pkt->side_data[elems].size = size;
239 pkt->side_data[elems].type = type;
240 pkt->side_data_elems++;
241
242 return pkt->side_data[elems].data;
243 }
244
245 uint8_t *av_packet_get_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
246 int *size)
247 {
248 int i;
249
250 for (i = 0; i < pkt->side_data_elems; i++) {
251 if (pkt->side_data[i].type == type) {
252 if (size)
253 *size = pkt->side_data[i].size;
254 return pkt->side_data[i].data;
255 }
256 }
257 return NULL;
258 }
259
260 int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
261 int size)
262 {
263 int i;
264
265 for (i = 0; i < pkt->side_data_elems; i++) {
266 if (pkt->side_data[i].type == type) {
267 if (size > pkt->side_data[i].size)
268 return AVERROR(ENOMEM);
269 pkt->side_data[i].size = size;
270 return 0;
271 }
272 }
273 return AVERROR(ENOENT);
274 }
275
276 int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
277 {
278 int i;
279
280 dst->pts = src->pts;
281 dst->dts = src->dts;
282 dst->pos = src->pos;
283 dst->duration = src->duration;
284 #if FF_API_CONVERGENCE_DURATION
285 FF_DISABLE_DEPRECATION_WARNINGS
286 dst->convergence_duration = src->convergence_duration;
287 FF_ENABLE_DEPRECATION_WARNINGS
288 #endif
289 dst->flags = src->flags;
290 dst->stream_index = src->stream_index;
291
292 for (i = 0; i < src->side_data_elems; i++) {
293 enum AVPacketSideDataType type = src->side_data[i].type;
294 int size = src->side_data[i].size;
295 uint8_t *src_data = src->side_data[i].data;
296 uint8_t *dst_data = av_packet_new_side_data(dst, type, size);
297
298 if (!dst_data) {
299 av_packet_free_side_data(dst);
300 return AVERROR(ENOMEM);
301 }
302 memcpy(dst_data, src_data, size);
303 }
304
305 return 0;
306 }
307
308 void av_packet_unref(AVPacket *pkt)
309 {
310 av_packet_free_side_data(pkt);
311 av_buffer_unref(&pkt->buf);
312 av_init_packet(pkt);
313 pkt->data = NULL;
314 pkt->size = 0;
315 }
316
317 int av_packet_ref(AVPacket *dst, AVPacket *src)
318 {
319 int ret;
320
321 ret = av_packet_copy_props(dst, src);
322 if (ret < 0)
323 return ret;
324
325 if (!src->buf) {
326 ret = packet_alloc(&dst->buf, src->size);
327 if (ret < 0)
328 goto fail;
329 memcpy(dst->buf->data, src->data, src->size);
330 } else {
331 dst->buf = av_buffer_ref(src->buf);
332 if (!dst->buf) {
333 ret = AVERROR(ENOMEM);
334 goto fail;
335 }
336 }
337
338 dst->size = src->size;
339 dst->data = dst->buf->data;
340 return 0;
341 fail:
342 av_packet_free_side_data(dst);
343 return ret;
344 }
345
346 void av_packet_move_ref(AVPacket *dst, AVPacket *src)
347 {
348 *dst = *src;
349 av_init_packet(src);
350 }
351
352 void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)
353 {
354 if (pkt->pts != AV_NOPTS_VALUE)
355 pkt->pts = av_rescale_q(pkt->pts, src_tb, dst_tb);
356 if (pkt->dts != AV_NOPTS_VALUE)
357 pkt->dts = av_rescale_q(pkt->dts, src_tb, dst_tb);
358 if (pkt->duration > 0)
359 pkt->duration = av_rescale_q(pkt->duration, src_tb, dst_tb);
360 #if FF_API_CONVERGENCE_DURATION
361 FF_DISABLE_DEPRECATION_WARNINGS
362 if (pkt->convergence_duration > 0)
363 pkt->convergence_duration = av_rescale_q(pkt->convergence_duration, src_tb, dst_tb);
364 FF_ENABLE_DEPRECATION_WARNINGS
365 #endif
366 }