]> git.sesse.net Git - ffmpeg/blob - libavcodec/avpacket.c
wmadec: require block_align to be set.
[ffmpeg] / 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/mem.h"
27 #include "avcodec.h"
28
29 #if FF_API_DESTRUCT_PACKET
30 void av_destruct_packet(AVPacket *pkt)
31 {
32     av_free(pkt->data);
33     pkt->data = NULL;
34     pkt->size = 0;
35 }
36
37 /* a dummy destruct callback for the callers that assume AVPacket.destruct ==
38  * NULL => static data */
39 static void dummy_destruct_packet(AVPacket *pkt)
40 {
41     av_assert0(0);
42 }
43 #endif
44
45 void av_init_packet(AVPacket *pkt)
46 {
47     pkt->pts                  = AV_NOPTS_VALUE;
48     pkt->dts                  = AV_NOPTS_VALUE;
49     pkt->pos                  = -1;
50     pkt->duration             = 0;
51     pkt->convergence_duration = 0;
52     pkt->flags                = 0;
53     pkt->stream_index         = 0;
54 #if FF_API_DESTRUCT_PACKET
55     pkt->destruct             = NULL;
56 #endif
57     pkt->buf                  = NULL;
58     pkt->side_data            = NULL;
59     pkt->side_data_elems      = 0;
60 }
61
62 int av_new_packet(AVPacket *pkt, int size)
63 {
64     AVBufferRef *buf = NULL;
65
66     if ((unsigned)size >= (unsigned)size + FF_INPUT_BUFFER_PADDING_SIZE)
67         return AVERROR(EINVAL);
68
69     av_buffer_realloc(&buf, size + FF_INPUT_BUFFER_PADDING_SIZE);
70     if (!buf)
71         return AVERROR(ENOMEM);
72
73     memset(buf->data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
74
75     av_init_packet(pkt);
76     pkt->buf      = buf;
77     pkt->data     = buf->data;
78     pkt->size     = size;
79 #if FF_API_DESTRUCT_PACKET
80     pkt->destruct = dummy_destruct_packet;
81 #endif
82
83     return 0;
84 }
85
86 void av_shrink_packet(AVPacket *pkt, int size)
87 {
88     if (pkt->size <= size)
89         return;
90     pkt->size = size;
91     memset(pkt->data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
92 }
93
94 int av_grow_packet(AVPacket *pkt, int grow_by)
95 {
96     int new_size;
97     av_assert0((unsigned)pkt->size <= INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE);
98     if (!pkt->size)
99         return av_new_packet(pkt, grow_by);
100     if ((unsigned)grow_by >
101         INT_MAX - (pkt->size + FF_INPUT_BUFFER_PADDING_SIZE))
102         return -1;
103
104     new_size = pkt->size + grow_by + FF_INPUT_BUFFER_PADDING_SIZE;
105     if (pkt->buf) {
106         int ret = av_buffer_realloc(&pkt->buf, new_size);
107         if (ret < 0)
108             return ret;
109     } else {
110         pkt->buf = av_buffer_alloc(new_size);
111         if (!pkt->buf)
112             return AVERROR(ENOMEM);
113         memcpy(pkt->buf->data, pkt->data, FFMIN(pkt->size, pkt->size + grow_by));
114 #if FF_API_DESTRUCT_PACKET
115         pkt->destruct = dummy_destruct_packet;
116 #endif
117     }
118     pkt->data  = pkt->buf->data;
119     pkt->size += grow_by;
120     memset(pkt->data + pkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
121
122     return 0;
123 }
124
125 int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size)
126 {
127     if (size >= INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE)
128         return AVERROR(EINVAL);
129
130     pkt->buf = av_buffer_create(data, size + FF_INPUT_BUFFER_PADDING_SIZE,
131                                 av_buffer_default_free, NULL, 0);
132     if (!pkt->buf)
133         return AVERROR(ENOMEM);
134
135     pkt->data = data;
136     pkt->size = size;
137 #if FF_API_DESTRUCT_PACKET
138     pkt->destruct = dummy_destruct_packet;
139 #endif
140
141     return 0;
142 }
143
144 #define ALLOC_MALLOC(data, size) data = av_malloc(size)
145 #define ALLOC_BUF(data, size)                \
146 do {                                         \
147     av_buffer_realloc(&pkt->buf, size);      \
148     data = pkt->buf ? pkt->buf->data : NULL; \
149 } while (0)
150
151 #define DUP_DATA(dst, src, size, padding, ALLOC)                        \
152     do {                                                                \
153         void *data;                                                     \
154         if (padding) {                                                  \
155             if ((unsigned)(size) >                                      \
156                 (unsigned)(size) + FF_INPUT_BUFFER_PADDING_SIZE)        \
157                 goto failed_alloc;                                      \
158             ALLOC(data, size + FF_INPUT_BUFFER_PADDING_SIZE);           \
159         } else {                                                        \
160             ALLOC(data, size);                                          \
161         }                                                               \
162         if (!data)                                                      \
163             goto failed_alloc;                                          \
164         memcpy(data, src, size);                                        \
165         if (padding)                                                    \
166             memset((uint8_t *)data + size, 0,                           \
167                    FF_INPUT_BUFFER_PADDING_SIZE);                       \
168         dst = data;                                                     \
169     } while (0)
170
171 int av_dup_packet(AVPacket *pkt)
172 {
173     AVPacket tmp_pkt;
174
175     if (!pkt->buf && pkt->data
176 #if FF_API_DESTRUCT_PACKET
177         && !pkt->destruct
178 #endif
179         ) {
180         tmp_pkt = *pkt;
181
182         pkt->data      = NULL;
183         pkt->side_data = NULL;
184         DUP_DATA(pkt->data, tmp_pkt.data, pkt->size, 1, ALLOC_BUF);
185 #if FF_API_DESTRUCT_PACKET
186         pkt->destruct = dummy_destruct_packet;
187 #endif
188
189         if (pkt->side_data_elems) {
190             int i;
191
192             DUP_DATA(pkt->side_data, tmp_pkt.side_data,
193                      pkt->side_data_elems * sizeof(*pkt->side_data), 0, ALLOC_MALLOC);
194             memset(pkt->side_data, 0,
195                    pkt->side_data_elems * sizeof(*pkt->side_data));
196             for (i = 0; i < pkt->side_data_elems; i++)
197                 DUP_DATA(pkt->side_data[i].data, tmp_pkt.side_data[i].data,
198                          tmp_pkt.side_data[i].size, 1, ALLOC_MALLOC);
199         }
200     }
201     return 0;
202
203 failed_alloc:
204     av_free_packet(pkt);
205     return AVERROR(ENOMEM);
206 }
207
208 void av_free_packet(AVPacket *pkt)
209 {
210     if (pkt) {
211         int i;
212
213         if (pkt->buf)
214             av_buffer_unref(&pkt->buf);
215 #if FF_API_DESTRUCT_PACKET
216         else if (pkt->destruct)
217             pkt->destruct(pkt);
218         pkt->destruct = NULL;
219 #endif
220         pkt->data            = NULL;
221         pkt->size            = 0;
222
223         for (i = 0; i < pkt->side_data_elems; i++)
224             av_free(pkt->side_data[i].data);
225         av_freep(&pkt->side_data);
226         pkt->side_data_elems = 0;
227     }
228 }
229
230 uint8_t *av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
231                                  int size)
232 {
233     int elems = pkt->side_data_elems;
234
235     if ((unsigned)elems + 1 > INT_MAX / sizeof(*pkt->side_data))
236         return NULL;
237     if ((unsigned)size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE)
238         return NULL;
239
240     pkt->side_data = av_realloc(pkt->side_data,
241                                 (elems + 1) * sizeof(*pkt->side_data));
242     if (!pkt->side_data)
243         return NULL;
244
245     pkt->side_data[elems].data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
246     if (!pkt->side_data[elems].data)
247         return NULL;
248     pkt->side_data[elems].size = size;
249     pkt->side_data[elems].type = type;
250     pkt->side_data_elems++;
251
252     return pkt->side_data[elems].data;
253 }
254
255 uint8_t *av_packet_get_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
256                                  int *size)
257 {
258     int i;
259
260     for (i = 0; i < pkt->side_data_elems; i++) {
261         if (pkt->side_data[i].type == type) {
262             if (size)
263                 *size = pkt->side_data[i].size;
264             return pkt->side_data[i].data;
265         }
266     }
267     return NULL;
268 }
269
270 int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
271                                int size)
272 {
273     int i;
274
275     for (i = 0; i < pkt->side_data_elems; i++) {
276         if (pkt->side_data[i].type == type) {
277             if (size > pkt->side_data[i].size)
278                 return AVERROR(ENOMEM);
279             pkt->side_data[i].size = size;
280             return 0;
281         }
282     }
283     return AVERROR(ENOENT);
284 }