Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * AVPacket functions for libavcodec |
||
3 | * Copyright (c) 2000, 2001, 2002 Fabrice Bellard |
||
4 | * |
||
5 | * This file is part of FFmpeg. |
||
6 | * |
||
7 | * FFmpeg 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 | * FFmpeg 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 FFmpeg; if not, write to the Free Software |
||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||
20 | */ |
||
21 | |||
22 | #include |
||
23 | |||
24 | #include "libavutil/avassert.h" |
||
25 | #include "libavutil/common.h" |
||
26 | #include "libavutil/internal.h" |
||
27 | #include "libavutil/mem.h" |
||
28 | #include "avcodec.h" |
||
29 | #include "bytestream.h" |
||
30 | #include "internal.h" |
||
31 | |||
32 | #if FF_API_DESTRUCT_PACKET |
||
33 | |||
34 | void av_destruct_packet(AVPacket *pkt) |
||
35 | { |
||
36 | av_free(pkt->data); |
||
37 | pkt->data = NULL; |
||
38 | pkt->size = 0; |
||
39 | } |
||
40 | |||
41 | /* a dummy destruct callback for the callers that assume AVPacket.destruct == |
||
42 | * NULL => static data */ |
||
43 | static void dummy_destruct_packet(AVPacket *pkt) |
||
44 | { |
||
45 | av_assert0(0); |
||
46 | } |
||
47 | #endif |
||
48 | |||
49 | void av_init_packet(AVPacket *pkt) |
||
50 | { |
||
51 | pkt->pts = AV_NOPTS_VALUE; |
||
52 | pkt->dts = AV_NOPTS_VALUE; |
||
53 | pkt->pos = -1; |
||
54 | pkt->duration = 0; |
||
55 | pkt->convergence_duration = 0; |
||
56 | pkt->flags = 0; |
||
57 | pkt->stream_index = 0; |
||
58 | #if FF_API_DESTRUCT_PACKET |
||
59 | FF_DISABLE_DEPRECATION_WARNINGS |
||
60 | pkt->destruct = NULL; |
||
61 | FF_ENABLE_DEPRECATION_WARNINGS |
||
62 | #endif |
||
63 | pkt->buf = NULL; |
||
64 | pkt->side_data = NULL; |
||
65 | pkt->side_data_elems = 0; |
||
66 | } |
||
67 | |||
68 | static int packet_alloc(AVBufferRef **buf, int size) |
||
69 | { |
||
70 | int ret; |
||
71 | if ((unsigned)size >= (unsigned)size + FF_INPUT_BUFFER_PADDING_SIZE) |
||
72 | return AVERROR(EINVAL); |
||
73 | |||
74 | ret = av_buffer_realloc(buf, size + FF_INPUT_BUFFER_PADDING_SIZE); |
||
75 | if (ret < 0) |
||
76 | return ret; |
||
77 | |||
78 | memset((*buf)->data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); |
||
79 | |||
80 | return 0; |
||
81 | } |
||
82 | |||
83 | int av_new_packet(AVPacket *pkt, int size) |
||
84 | { |
||
85 | AVBufferRef *buf = NULL; |
||
86 | int ret = packet_alloc(&buf, size); |
||
87 | if (ret < 0) |
||
88 | return ret; |
||
89 | |||
90 | av_init_packet(pkt); |
||
91 | pkt->buf = buf; |
||
92 | pkt->data = buf->data; |
||
93 | pkt->size = size; |
||
94 | #if FF_API_DESTRUCT_PACKET |
||
95 | FF_DISABLE_DEPRECATION_WARNINGS |
||
96 | pkt->destruct = dummy_destruct_packet; |
||
97 | FF_ENABLE_DEPRECATION_WARNINGS |
||
98 | #endif |
||
99 | |||
100 | return 0; |
||
101 | } |
||
102 | |||
103 | void av_shrink_packet(AVPacket *pkt, int size) |
||
104 | { |
||
105 | if (pkt->size <= size) |
||
106 | return; |
||
107 | pkt->size = size; |
||
108 | memset(pkt->data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); |
||
109 | } |
||
110 | |||
111 | int av_grow_packet(AVPacket *pkt, int grow_by) |
||
112 | { |
||
113 | int new_size; |
||
114 | av_assert0((unsigned)pkt->size <= INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE); |
||
115 | if (!pkt->size) |
||
116 | return av_new_packet(pkt, grow_by); |
||
117 | if ((unsigned)grow_by > |
||
118 | INT_MAX - (pkt->size + FF_INPUT_BUFFER_PADDING_SIZE)) |
||
119 | return -1; |
||
120 | |||
121 | new_size = pkt->size + grow_by + FF_INPUT_BUFFER_PADDING_SIZE; |
||
122 | if (pkt->buf) { |
||
123 | int ret = av_buffer_realloc(&pkt->buf, new_size); |
||
124 | if (ret < 0) |
||
125 | return ret; |
||
126 | } else { |
||
127 | pkt->buf = av_buffer_alloc(new_size); |
||
128 | if (!pkt->buf) |
||
129 | return AVERROR(ENOMEM); |
||
130 | memcpy(pkt->buf->data, pkt->data, FFMIN(pkt->size, pkt->size + grow_by)); |
||
131 | #if FF_API_DESTRUCT_PACKET |
||
132 | FF_DISABLE_DEPRECATION_WARNINGS |
||
133 | pkt->destruct = dummy_destruct_packet; |
||
134 | FF_ENABLE_DEPRECATION_WARNINGS |
||
135 | #endif |
||
136 | } |
||
137 | pkt->data = pkt->buf->data; |
||
138 | pkt->size += grow_by; |
||
139 | memset(pkt->data + pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE); |
||
140 | |||
141 | return 0; |
||
142 | } |
||
143 | |||
144 | int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size) |
||
145 | { |
||
146 | if (size >= INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE) |
||
147 | return AVERROR(EINVAL); |
||
148 | |||
149 | pkt->buf = av_buffer_create(data, size + FF_INPUT_BUFFER_PADDING_SIZE, |
||
150 | av_buffer_default_free, NULL, 0); |
||
151 | if (!pkt->buf) |
||
152 | return AVERROR(ENOMEM); |
||
153 | |||
154 | pkt->data = data; |
||
155 | pkt->size = size; |
||
156 | #if FF_API_DESTRUCT_PACKET |
||
157 | FF_DISABLE_DEPRECATION_WARNINGS |
||
158 | pkt->destruct = dummy_destruct_packet; |
||
159 | FF_ENABLE_DEPRECATION_WARNINGS |
||
160 | #endif |
||
161 | |||
162 | return 0; |
||
163 | } |
||
164 | |||
165 | #define ALLOC_MALLOC(data, size) data = av_malloc(size) |
||
166 | #define ALLOC_BUF(data, size) \ |
||
167 | do { \ |
||
168 | av_buffer_realloc(&pkt->buf, size); \ |
||
169 | data = pkt->buf ? pkt->buf->data : NULL; \ |
||
170 | } while (0) |
||
171 | |||
172 | #define DUP_DATA(dst, src, size, padding, ALLOC) \ |
||
173 | do { \ |
||
174 | void *data; \ |
||
175 | if (padding) { \ |
||
176 | if ((unsigned)(size) > \ |
||
177 | (unsigned)(size) + FF_INPUT_BUFFER_PADDING_SIZE) \ |
||
178 | goto failed_alloc; \ |
||
179 | ALLOC(data, size + FF_INPUT_BUFFER_PADDING_SIZE); \ |
||
180 | } else { \ |
||
181 | ALLOC(data, size); \ |
||
182 | } \ |
||
183 | if (!data) \ |
||
184 | goto failed_alloc; \ |
||
185 | memcpy(data, src, size); \ |
||
186 | if (padding) \ |
||
187 | memset((uint8_t *)data + size, 0, \ |
||
188 | FF_INPUT_BUFFER_PADDING_SIZE); \ |
||
189 | dst = data; \ |
||
190 | } while (0) |
||
191 | |||
192 | /* Makes duplicates of data, side_data, but does not copy any other fields */ |
||
193 | static int copy_packet_data(AVPacket *pkt, AVPacket *src, int dup) |
||
194 | { |
||
195 | pkt->data = NULL; |
||
196 | pkt->side_data = NULL; |
||
197 | if (pkt->buf) { |
||
198 | AVBufferRef *ref = av_buffer_ref(src->buf); |
||
199 | if (!ref) |
||
200 | return AVERROR(ENOMEM); |
||
201 | pkt->buf = ref; |
||
202 | pkt->data = ref->data; |
||
203 | } else { |
||
204 | DUP_DATA(pkt->data, src->data, pkt->size, 1, ALLOC_BUF); |
||
205 | } |
||
206 | #if FF_API_DESTRUCT_PACKET |
||
207 | FF_DISABLE_DEPRECATION_WARNINGS |
||
208 | pkt->destruct = dummy_destruct_packet; |
||
209 | FF_ENABLE_DEPRECATION_WARNINGS |
||
210 | #endif |
||
211 | if (pkt->side_data_elems && dup) |
||
212 | pkt->side_data = src->side_data; |
||
213 | if (pkt->side_data_elems && !dup) { |
||
214 | return av_copy_packet_side_data(pkt, src); |
||
215 | } |
||
216 | return 0; |
||
217 | |||
218 | failed_alloc: |
||
219 | av_free_packet(pkt); |
||
220 | return AVERROR(ENOMEM); |
||
221 | } |
||
222 | |||
223 | int av_copy_packet_side_data(AVPacket *pkt, AVPacket *src) |
||
224 | { |
||
225 | if (src->side_data_elems) { |
||
226 | int i; |
||
227 | DUP_DATA(pkt->side_data, src->side_data, |
||
228 | src->side_data_elems * sizeof(*src->side_data), 0, ALLOC_MALLOC); |
||
229 | if (src != pkt) { |
||
230 | memset(pkt->side_data, 0, |
||
231 | src->side_data_elems * sizeof(*src->side_data)); |
||
232 | } |
||
233 | for (i = 0; i < src->side_data_elems; i++) { |
||
234 | DUP_DATA(pkt->side_data[i].data, src->side_data[i].data, |
||
235 | src->side_data[i].size, 1, ALLOC_MALLOC); |
||
236 | pkt->side_data[i].size = src->side_data[i].size; |
||
237 | pkt->side_data[i].type = src->side_data[i].type; |
||
238 | } |
||
239 | } |
||
240 | return 0; |
||
241 | |||
242 | failed_alloc: |
||
243 | av_free_packet(pkt); |
||
244 | return AVERROR(ENOMEM); |
||
245 | } |
||
246 | |||
247 | int av_dup_packet(AVPacket *pkt) |
||
248 | { |
||
249 | AVPacket tmp_pkt; |
||
250 | |||
251 | FF_DISABLE_DEPRECATION_WARNINGS |
||
252 | if (!pkt->buf && pkt->data |
||
253 | #if FF_API_DESTRUCT_PACKET |
||
254 | && !pkt->destruct |
||
255 | #endif |
||
256 | ) { |
||
257 | FF_ENABLE_DEPRECATION_WARNINGS |
||
258 | tmp_pkt = *pkt; |
||
259 | return copy_packet_data(pkt, &tmp_pkt, 1); |
||
260 | } |
||
261 | return 0; |
||
262 | } |
||
263 | |||
264 | int av_copy_packet(AVPacket *dst, AVPacket *src) |
||
265 | { |
||
266 | *dst = *src; |
||
267 | return copy_packet_data(dst, src, 0); |
||
268 | } |
||
269 | |||
270 | void av_packet_free_side_data(AVPacket *pkt) |
||
271 | { |
||
272 | int i; |
||
273 | for (i = 0; i < pkt->side_data_elems; i++) |
||
274 | av_free(pkt->side_data[i].data); |
||
275 | av_freep(&pkt->side_data); |
||
276 | pkt->side_data_elems = 0; |
||
277 | } |
||
278 | |||
279 | void av_free_packet(AVPacket *pkt) |
||
280 | { |
||
281 | if (pkt) { |
||
282 | FF_DISABLE_DEPRECATION_WARNINGS |
||
283 | if (pkt->buf) |
||
284 | av_buffer_unref(&pkt->buf); |
||
285 | #if FF_API_DESTRUCT_PACKET |
||
286 | else if (pkt->destruct) |
||
287 | pkt->destruct(pkt); |
||
288 | pkt->destruct = NULL; |
||
289 | #endif |
||
290 | FF_ENABLE_DEPRECATION_WARNINGS |
||
291 | pkt->data = NULL; |
||
292 | pkt->size = 0; |
||
293 | |||
294 | av_packet_free_side_data(pkt); |
||
295 | } |
||
296 | } |
||
297 | |||
298 | uint8_t *av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, |
||
299 | int size) |
||
300 | { |
||
301 | int elems = pkt->side_data_elems; |
||
302 | |||
303 | if ((unsigned)elems + 1 > INT_MAX / sizeof(*pkt->side_data)) |
||
304 | return NULL; |
||
305 | if ((unsigned)size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE) |
||
306 | return NULL; |
||
307 | |||
308 | pkt->side_data = av_realloc(pkt->side_data, |
||
309 | (elems + 1) * sizeof(*pkt->side_data)); |
||
310 | if (!pkt->side_data) |
||
311 | return NULL; |
||
312 | |||
313 | pkt->side_data[elems].data = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE); |
||
314 | if (!pkt->side_data[elems].data) |
||
315 | return NULL; |
||
316 | pkt->side_data[elems].size = size; |
||
317 | pkt->side_data[elems].type = type; |
||
318 | pkt->side_data_elems++; |
||
319 | |||
320 | return pkt->side_data[elems].data; |
||
321 | } |
||
322 | |||
323 | uint8_t *av_packet_get_side_data(AVPacket *pkt, enum AVPacketSideDataType type, |
||
324 | int *size) |
||
325 | { |
||
326 | int i; |
||
327 | |||
328 | for (i = 0; i < pkt->side_data_elems; i++) { |
||
329 | if (pkt->side_data[i].type == type) { |
||
330 | if (size) |
||
331 | *size = pkt->side_data[i].size; |
||
332 | return pkt->side_data[i].data; |
||
333 | } |
||
334 | } |
||
335 | return NULL; |
||
336 | } |
||
337 | |||
338 | #define FF_MERGE_MARKER 0x8c4d9d108e25e9feULL |
||
339 | |||
340 | int av_packet_merge_side_data(AVPacket *pkt){ |
||
341 | if(pkt->side_data_elems){ |
||
342 | AVBufferRef *buf; |
||
343 | int i; |
||
344 | uint8_t *p; |
||
345 | uint64_t size= pkt->size + 8LL + FF_INPUT_BUFFER_PADDING_SIZE; |
||
346 | AVPacket old= *pkt; |
||
347 | for (i=0; i |
||
348 | size += old.side_data[i].size + 5LL; |
||
349 | } |
||
350 | if (size > INT_MAX) |
||
351 | return AVERROR(EINVAL); |
||
352 | buf = av_buffer_alloc(size); |
||
353 | if (!buf) |
||
354 | return AVERROR(ENOMEM); |
||
355 | pkt->buf = buf; |
||
356 | pkt->data = p = buf->data; |
||
357 | #if FF_API_DESTRUCT_PACKET |
||
358 | FF_DISABLE_DEPRECATION_WARNINGS |
||
359 | pkt->destruct = dummy_destruct_packet; |
||
360 | FF_ENABLE_DEPRECATION_WARNINGS |
||
361 | #endif |
||
362 | pkt->size = size - FF_INPUT_BUFFER_PADDING_SIZE; |
||
363 | bytestream_put_buffer(&p, old.data, old.size); |
||
364 | for (i=old.side_data_elems-1; i>=0; i--) { |
||
365 | bytestream_put_buffer(&p, old.side_data[i].data, old.side_data[i].size); |
||
366 | bytestream_put_be32(&p, old.side_data[i].size); |
||
367 | *p++ = old.side_data[i].type | ((i==old.side_data_elems-1)*128); |
||
368 | } |
||
369 | bytestream_put_be64(&p, FF_MERGE_MARKER); |
||
370 | av_assert0(p-pkt->data == pkt->size); |
||
371 | memset(p, 0, FF_INPUT_BUFFER_PADDING_SIZE); |
||
372 | av_free_packet(&old); |
||
373 | pkt->side_data_elems = 0; |
||
374 | pkt->side_data = NULL; |
||
375 | return 1; |
||
376 | } |
||
377 | return 0; |
||
378 | } |
||
379 | |||
380 | int av_packet_split_side_data(AVPacket *pkt){ |
||
381 | if (!pkt->side_data_elems && pkt->size >12 && AV_RB64(pkt->data + pkt->size - 8) == FF_MERGE_MARKER){ |
||
382 | int i; |
||
383 | unsigned int size, orig_pktsize = pkt->size; |
||
384 | uint8_t *p; |
||
385 | |||
386 | p = pkt->data + pkt->size - 8 - 5; |
||
387 | for (i=1; ; i++){ |
||
388 | size = AV_RB32(p); |
||
389 | if (size>INT_MAX || p - pkt->data < size) |
||
390 | return 0; |
||
391 | if (p[4]&128) |
||
392 | break; |
||
393 | p-= size+5; |
||
394 | } |
||
395 | |||
396 | pkt->side_data = av_malloc(i * sizeof(*pkt->side_data)); |
||
397 | if (!pkt->side_data) |
||
398 | return AVERROR(ENOMEM); |
||
399 | |||
400 | p= pkt->data + pkt->size - 8 - 5; |
||
401 | for (i=0; ; i++){ |
||
402 | size= AV_RB32(p); |
||
403 | av_assert0(size<=INT_MAX && p - pkt->data >= size); |
||
404 | pkt->side_data[i].data = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE); |
||
405 | pkt->side_data[i].size = size; |
||
406 | pkt->side_data[i].type = p[4]&127; |
||
407 | if (!pkt->side_data[i].data) |
||
408 | return AVERROR(ENOMEM); |
||
409 | memcpy(pkt->side_data[i].data, p-size, size); |
||
410 | pkt->size -= size + 5; |
||
411 | if(p[4]&128) |
||
412 | break; |
||
413 | p-= size+5; |
||
414 | } |
||
415 | pkt->size -= 8; |
||
416 | /* FFMIN() prevents overflow in case the packet wasn't allocated with |
||
417 | * proper padding. |
||
418 | * If the side data is smaller than the buffer padding size, the |
||
419 | * remaining bytes should have already been filled with zeros by the |
||
420 | * original packet allocation anyway. */ |
||
421 | memset(pkt->data + pkt->size, 0, |
||
422 | FFMIN(orig_pktsize - pkt->size, FF_INPUT_BUFFER_PADDING_SIZE)); |
||
423 | pkt->side_data_elems = i+1; |
||
424 | return 1; |
||
425 | } |
||
426 | return 0; |
||
427 | } |
||
428 | |||
429 | int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type, |
||
430 | int size) |
||
431 | { |
||
432 | int i; |
||
433 | |||
434 | for (i = 0; i < pkt->side_data_elems; i++) { |
||
435 | if (pkt->side_data[i].type == type) { |
||
436 | if (size > pkt->side_data[i].size) |
||
437 | return AVERROR(ENOMEM); |
||
438 | pkt->side_data[i].size = size; |
||
439 | return 0; |
||
440 | } |
||
441 | } |
||
442 | return AVERROR(ENOENT); |
||
443 | } |
||
444 | |||
445 | int av_packet_copy_props(AVPacket *dst, const AVPacket *src) |
||
446 | { |
||
447 | int i; |
||
448 | |||
449 | dst->pts = src->pts; |
||
450 | dst->dts = src->dts; |
||
451 | dst->pos = src->pos; |
||
452 | dst->duration = src->duration; |
||
453 | dst->convergence_duration = src->convergence_duration; |
||
454 | dst->flags = src->flags; |
||
455 | dst->stream_index = src->stream_index; |
||
456 | dst->side_data_elems = src->side_data_elems; |
||
457 | |||
458 | for (i = 0; i < src->side_data_elems; i++) { |
||
459 | enum AVPacketSideDataType type = src->side_data[i].type; |
||
460 | int size = src->side_data[i].size; |
||
461 | uint8_t *src_data = src->side_data[i].data; |
||
462 | uint8_t *dst_data = av_packet_new_side_data(dst, type, size); |
||
463 | |||
464 | if (!dst_data) { |
||
465 | av_packet_free_side_data(dst); |
||
466 | return AVERROR(ENOMEM); |
||
467 | } |
||
468 | memcpy(dst_data, src_data, size); |
||
469 | } |
||
470 | |||
471 | return 0; |
||
472 | } |
||
473 | |||
474 | void av_packet_unref(AVPacket *pkt) |
||
475 | { |
||
476 | av_packet_free_side_data(pkt); |
||
477 | av_buffer_unref(&pkt->buf); |
||
478 | av_init_packet(pkt); |
||
479 | pkt->data = NULL; |
||
480 | pkt->size = 0; |
||
481 | } |
||
482 | |||
483 | int av_packet_ref(AVPacket *dst, AVPacket *src) |
||
484 | { |
||
485 | int ret; |
||
486 | |||
487 | ret = av_packet_copy_props(dst, src); |
||
488 | if (ret < 0) |
||
489 | return ret; |
||
490 | |||
491 | if (!src->buf) { |
||
492 | ret = packet_alloc(&dst->buf, src->size); |
||
493 | if (ret < 0) |
||
494 | goto fail; |
||
495 | memcpy(dst->buf->data, src->data, src->size); |
||
496 | } else |
||
497 | dst->buf = av_buffer_ref(src->buf); |
||
498 | |||
499 | dst->size = src->size; |
||
500 | dst->data = dst->buf->data; |
||
501 | return 0; |
||
502 | fail: |
||
503 | av_packet_free_side_data(dst); |
||
504 | return ret; |
||
505 | } |
||
506 | |||
507 | void av_packet_move_ref(AVPacket *dst, AVPacket *src) |
||
508 | { |
||
509 | *dst = *src; |
||
510 | av_init_packet(src); |
||
511 | }>>>>=INT_MAX>>>>>>=>=>>> |