Mercurial > libavformat.hg
annotate smacker.c @ 4037:5f65cbe25494 libavformat
Fix memleak caused by the fact that url_open_buf() allocates a context
when calling, but url_close_buf() doesn't free it. The better solution
is to not allocate it at all, init it with init_put_byte() and then
not have to close it at all. In the case where we do need to hold it
around for longer than within the function context, we allocate it with
av_alloc_put_byte() and free it with av_free() instead. Discussed in ML
thread "[PATCH] fix small memleak in rdt.c".
author | rbultje |
---|---|
date | Mon, 17 Nov 2008 14:23:20 +0000 |
parents | 549a09cf23fe |
children | 7d2f3f1b68d8 |
rev | line source |
---|---|
1019 | 1 /* |
1415
3b00fb8ef8e4
replace coder/decoder file description in libavformat by muxer/demuxer
aurel
parents:
1358
diff
changeset
|
2 * Smacker demuxer |
1019 | 3 * Copyright (c) 2006 Konstantin Shishkov. |
4 * | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1172
diff
changeset
|
5 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1172
diff
changeset
|
6 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1172
diff
changeset
|
7 * FFmpeg is free software; you can redistribute it and/or |
1019 | 8 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1172
diff
changeset
|
10 * version 2.1 of the License, or (at your option) any later version. |
1019 | 11 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1172
diff
changeset
|
12 * FFmpeg is distributed in the hope that it will be useful, |
1019 | 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 | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1172
diff
changeset
|
18 * License along with FFmpeg; if not, write to the Free Software |
1019 | 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 */ | |
21 | |
22 /* | |
23 * Based on http://wiki.multimedia.cx/index.php?title=Smacker | |
24 */ | |
25 | |
3286 | 26 #include "libavutil/bswap.h" |
1019 | 27 #include "avformat.h" |
28 | |
29 #define SMACKER_PAL 0x01 | |
2404 | 30 #define SMACKER_FLAG_RING_FRAME 0x01 |
1019 | 31 |
32 enum SAudFlags { | |
33 SMK_AUD_PACKED = 0x80000000, | |
34 SMK_AUD_16BITS = 0x20000000, | |
35 SMK_AUD_STEREO = 0x10000000, | |
36 SMK_AUD_BINKAUD = 0x08000000, | |
37 SMK_AUD_USEDCT = 0x04000000 | |
38 }; | |
39 | |
40 typedef struct SmackerContext { | |
41 /* Smacker file header */ | |
42 uint32_t magic; | |
43 uint32_t width, height; | |
44 uint32_t frames; | |
45 int pts_inc; | |
46 uint32_t flags; | |
47 uint32_t audio[7]; | |
48 uint32_t treesize; | |
49 uint32_t mmap_size, mclr_size, full_size, type_size; | |
50 uint32_t rates[7]; | |
51 uint32_t pad; | |
52 /* frame info */ | |
53 uint32_t *frm_size; | |
54 uint8_t *frm_flags; | |
55 /* internal variables */ | |
56 int cur_frame; | |
57 int is_ver4; | |
58 int64_t cur_pts; | |
59 /* current frame for demuxing */ | |
60 uint8_t pal[768]; | |
61 int indexes[7]; | |
62 int videoindex; | |
63 uint8_t *bufs[7]; | |
64 int buf_sizes[7]; | |
65 int stream_id[7]; | |
66 int curstream; | |
3973
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3908
diff
changeset
|
67 int64_t nextpos; |
1090 | 68 int64_t aud_pts[7]; |
1019 | 69 } SmackerContext; |
70 | |
71 typedef struct SmackerFrame { | |
72 int64_t pts; | |
73 int stream; | |
74 } SmackerFrame; | |
75 | |
76 /* palette used in Smacker */ | |
77 static const uint8_t smk_pal[64] = { | |
78 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, | |
79 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C, | |
80 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D, | |
81 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, | |
82 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E, | |
83 0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE, | |
84 0xC3, 0xC7, 0xCB, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF, | |
85 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF | |
86 }; | |
87 | |
88 | |
89 static int smacker_probe(AVProbeData *p) | |
90 { | |
91 if(p->buf[0] == 'S' && p->buf[1] == 'M' && p->buf[2] == 'K' | |
92 && (p->buf[3] == '2' || p->buf[3] == '4')) | |
93 return AVPROBE_SCORE_MAX; | |
94 else | |
95 return 0; | |
96 } | |
97 | |
98 static int smacker_read_header(AVFormatContext *s, AVFormatParameters *ap) | |
99 { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
100 ByteIOContext *pb = s->pb; |
2006 | 101 SmackerContext *smk = s->priv_data; |
1019 | 102 AVStream *st, *ast[7]; |
103 int i, ret; | |
104 int tbase; | |
105 | |
106 /* read and check header */ | |
107 smk->magic = get_le32(pb); | |
108 if (smk->magic != MKTAG('S', 'M', 'K', '2') && smk->magic != MKTAG('S', 'M', 'K', '4')) | |
109 return -1; | |
110 smk->width = get_le32(pb); | |
111 smk->height = get_le32(pb); | |
112 smk->frames = get_le32(pb); | |
113 smk->pts_inc = (int32_t)get_le32(pb); | |
114 smk->flags = get_le32(pb); | |
2404 | 115 if(smk->flags & SMACKER_FLAG_RING_FRAME) |
116 smk->frames++; | |
1019 | 117 for(i = 0; i < 7; i++) |
118 smk->audio[i] = get_le32(pb); | |
119 smk->treesize = get_le32(pb); | |
1079 | 120 |
121 if(smk->treesize >= UINT_MAX/4){ // smk->treesize + 16 must not overflow (this check is probably redundant) | |
122 av_log(s, AV_LOG_ERROR, "treesize too large\n"); | |
123 return -1; | |
124 } | |
125 | |
126 //FIXME remove extradata "rebuilding" | |
1019 | 127 smk->mmap_size = get_le32(pb); |
128 smk->mclr_size = get_le32(pb); | |
129 smk->full_size = get_le32(pb); | |
130 smk->type_size = get_le32(pb); | |
131 for(i = 0; i < 7; i++) | |
132 smk->rates[i] = get_le32(pb); | |
133 smk->pad = get_le32(pb); | |
134 /* setup data */ | |
135 if(smk->frames > 0xFFFFFF) { | |
136 av_log(s, AV_LOG_ERROR, "Too many frames: %i\n", smk->frames); | |
137 return -1; | |
138 } | |
139 smk->frm_size = av_malloc(smk->frames * 4); | |
140 smk->frm_flags = av_malloc(smk->frames); | |
141 | |
142 smk->is_ver4 = (smk->magic != MKTAG('S', 'M', 'K', '2')); | |
143 | |
144 /* read frame info */ | |
145 for(i = 0; i < smk->frames; i++) { | |
146 smk->frm_size[i] = get_le32(pb); | |
147 } | |
148 for(i = 0; i < smk->frames; i++) { | |
149 smk->frm_flags[i] = get_byte(pb); | |
150 } | |
151 | |
152 /* init video codec */ | |
153 st = av_new_stream(s, 0); | |
154 if (!st) | |
155 return -1; | |
156 smk->videoindex = st->index; | |
157 st->codec->width = smk->width; | |
158 st->codec->height = smk->height; | |
159 st->codec->pix_fmt = PIX_FMT_PAL8; | |
160 st->codec->codec_type = CODEC_TYPE_VIDEO; | |
161 st->codec->codec_id = CODEC_ID_SMACKVIDEO; | |
1089
0319672689ef
Now MPlayer should understand Smacker audio and video codecs.
kostya
parents:
1079
diff
changeset
|
162 st->codec->codec_tag = smk->magic; |
1019 | 163 /* Smacker uses 100000 as internal timebase */ |
164 if(smk->pts_inc < 0) | |
165 smk->pts_inc = -smk->pts_inc; | |
166 else | |
167 smk->pts_inc *= 100; | |
168 tbase = 100000; | |
169 av_reduce(&tbase, &smk->pts_inc, tbase, smk->pts_inc, (1UL<<31)-1); | |
170 av_set_pts_info(st, 33, smk->pts_inc, tbase); | |
171 /* handle possible audio streams */ | |
172 for(i = 0; i < 7; i++) { | |
173 smk->indexes[i] = -1; | |
174 if((smk->rates[i] & 0xFFFFFF) && !(smk->rates[i] & SMK_AUD_BINKAUD)){ | |
175 ast[i] = av_new_stream(s, 0); | |
176 smk->indexes[i] = ast[i]->index; | |
177 ast[i]->codec->codec_type = CODEC_TYPE_AUDIO; | |
178 ast[i]->codec->codec_id = (smk->rates[i] & SMK_AUD_PACKED) ? CODEC_ID_SMACKAUDIO : CODEC_ID_PCM_U8; | |
1089
0319672689ef
Now MPlayer should understand Smacker audio and video codecs.
kostya
parents:
1079
diff
changeset
|
179 ast[i]->codec->codec_tag = MKTAG('S', 'M', 'K', 'A'); |
1019 | 180 ast[i]->codec->channels = (smk->rates[i] & SMK_AUD_STEREO) ? 2 : 1; |
181 ast[i]->codec->sample_rate = smk->rates[i] & 0xFFFFFF; | |
3908
1d3d17de20ba
Bump Major version, this commit is almost just renaming bits_per_sample to
michael
parents:
3424
diff
changeset
|
182 ast[i]->codec->bits_per_coded_sample = (smk->rates[i] & SMK_AUD_16BITS) ? 16 : 8; |
1d3d17de20ba
Bump Major version, this commit is almost just renaming bits_per_sample to
michael
parents:
3424
diff
changeset
|
183 if(ast[i]->codec->bits_per_coded_sample == 16 && ast[i]->codec->codec_id == CODEC_ID_PCM_U8) |
1019 | 184 ast[i]->codec->codec_id = CODEC_ID_PCM_S16LE; |
1090 | 185 av_set_pts_info(ast[i], 64, 1, ast[i]->codec->sample_rate |
3908
1d3d17de20ba
Bump Major version, this commit is almost just renaming bits_per_sample to
michael
parents:
3424
diff
changeset
|
186 * ast[i]->codec->channels * ast[i]->codec->bits_per_coded_sample / 8); |
1019 | 187 } |
188 } | |
189 | |
190 | |
191 /* load trees to extradata, they will be unpacked by decoder */ | |
192 st->codec->extradata = av_malloc(smk->treesize + 16); | |
193 st->codec->extradata_size = smk->treesize + 16; | |
194 if(!st->codec->extradata){ | |
195 av_log(s, AV_LOG_ERROR, "Cannot allocate %i bytes of extradata\n", smk->treesize + 16); | |
196 av_free(smk->frm_size); | |
197 av_free(smk->frm_flags); | |
198 return -1; | |
199 } | |
200 ret = get_buffer(pb, st->codec->extradata + 16, st->codec->extradata_size - 16); | |
201 if(ret != st->codec->extradata_size - 16){ | |
202 av_free(smk->frm_size); | |
203 av_free(smk->frm_flags); | |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
204 return AVERROR(EIO); |
1019 | 205 } |
206 ((int32_t*)st->codec->extradata)[0] = le2me_32(smk->mmap_size); | |
207 ((int32_t*)st->codec->extradata)[1] = le2me_32(smk->mclr_size); | |
208 ((int32_t*)st->codec->extradata)[2] = le2me_32(smk->full_size); | |
209 ((int32_t*)st->codec->extradata)[3] = le2me_32(smk->type_size); | |
210 | |
211 smk->curstream = -1; | |
212 smk->nextpos = url_ftell(pb); | |
213 | |
214 return 0; | |
215 } | |
216 | |
217 | |
218 static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) | |
219 { | |
2006 | 220 SmackerContext *smk = s->priv_data; |
1019 | 221 int flags; |
222 int ret; | |
223 int i; | |
224 int frame_size = 0; | |
225 int palchange = 0; | |
226 int pos; | |
227 | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
228 if (url_feof(s->pb) || smk->cur_frame >= smk->frames) |
1787
eb16c64144ee
This fixes error handling for BeOS, removing the need for some ifdefs.
mmu_man
parents:
1673
diff
changeset
|
229 return AVERROR(EIO); |
1019 | 230 |
231 /* if we demuxed all streams, pass another frame */ | |
232 if(smk->curstream < 0) { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
233 url_fseek(s->pb, smk->nextpos, 0); |
1019 | 234 frame_size = smk->frm_size[smk->cur_frame] & (~3); |
235 flags = smk->frm_flags[smk->cur_frame]; | |
236 /* handle palette change event */ | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
237 pos = url_ftell(s->pb); |
1019 | 238 if(flags & SMACKER_PAL){ |
239 int size, sz, t, off, j, pos; | |
240 uint8_t *pal = smk->pal; | |
241 uint8_t oldpal[768]; | |
242 | |
243 memcpy(oldpal, pal, 768); | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
244 size = get_byte(s->pb); |
1019 | 245 size = size * 4 - 1; |
246 frame_size -= size; | |
247 frame_size--; | |
248 sz = 0; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
249 pos = url_ftell(s->pb) + size; |
1019 | 250 while(sz < 256){ |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
251 t = get_byte(s->pb); |
1019 | 252 if(t & 0x80){ /* skip palette entries */ |
253 sz += (t & 0x7F) + 1; | |
254 pal += ((t & 0x7F) + 1) * 3; | |
255 } else if(t & 0x40){ /* copy with offset */ | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
256 off = get_byte(s->pb) * 3; |
1019 | 257 j = (t & 0x3F) + 1; |
258 while(j-- && sz < 256) { | |
259 *pal++ = oldpal[off + 0]; | |
260 *pal++ = oldpal[off + 1]; | |
261 *pal++ = oldpal[off + 2]; | |
262 sz++; | |
263 off += 3; | |
264 } | |
265 } else { /* new entries */ | |
266 *pal++ = smk_pal[t]; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
267 *pal++ = smk_pal[get_byte(s->pb) & 0x3F]; |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
268 *pal++ = smk_pal[get_byte(s->pb) & 0x3F]; |
1019 | 269 sz++; |
270 } | |
271 } | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
272 url_fseek(s->pb, pos, 0); |
1019 | 273 palchange |= 1; |
274 } | |
275 flags >>= 1; | |
276 smk->curstream = -1; | |
277 /* if audio chunks are present, put them to stack and retrieve later */ | |
278 for(i = 0; i < 7; i++) { | |
279 if(flags & 1) { | |
280 int size; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
281 size = get_le32(s->pb) - 4; |
1019 | 282 frame_size -= size; |
283 frame_size -= 4; | |
284 smk->curstream++; | |
285 smk->bufs[smk->curstream] = av_realloc(smk->bufs[smk->curstream], size); | |
286 smk->buf_sizes[smk->curstream] = size; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
287 ret = get_buffer(s->pb, smk->bufs[smk->curstream], size); |
1019 | 288 if(ret != size) |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
289 return AVERROR(EIO); |
1019 | 290 smk->stream_id[smk->curstream] = smk->indexes[i]; |
291 } | |
292 flags >>= 1; | |
293 } | |
294 if (av_new_packet(pkt, frame_size + 768)) | |
2273
7eb456c4ed8a
Replace all occurrences of AVERROR_NOMEM with AVERROR(ENOMEM).
takis
parents:
2006
diff
changeset
|
295 return AVERROR(ENOMEM); |
1019 | 296 if(smk->frm_size[smk->cur_frame] & 1) |
297 palchange |= 2; | |
298 pkt->data[0] = palchange; | |
299 memcpy(pkt->data + 1, smk->pal, 768); | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
300 ret = get_buffer(s->pb, pkt->data + 769, frame_size); |
1019 | 301 if(ret != frame_size) |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
302 return AVERROR(EIO); |
1019 | 303 pkt->stream_index = smk->videoindex; |
304 pkt->size = ret + 769; | |
305 smk->cur_frame++; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
306 smk->nextpos = url_ftell(s->pb); |
1019 | 307 } else { |
308 if (av_new_packet(pkt, smk->buf_sizes[smk->curstream])) | |
2273
7eb456c4ed8a
Replace all occurrences of AVERROR_NOMEM with AVERROR(ENOMEM).
takis
parents:
2006
diff
changeset
|
309 return AVERROR(ENOMEM); |
1019 | 310 memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]); |
311 pkt->size = smk->buf_sizes[smk->curstream]; | |
312 pkt->stream_index = smk->stream_id[smk->curstream]; | |
1090 | 313 pkt->pts = smk->aud_pts[smk->curstream]; |
1673 | 314 smk->aud_pts[smk->curstream] += AV_RL32(pkt->data); |
1019 | 315 smk->curstream--; |
316 } | |
317 | |
318 return 0; | |
319 } | |
320 | |
321 static int smacker_read_close(AVFormatContext *s) | |
322 { | |
2006 | 323 SmackerContext *smk = s->priv_data; |
1019 | 324 int i; |
325 | |
326 for(i = 0; i < 7; i++) | |
327 if(smk->bufs[i]) | |
328 av_free(smk->bufs[i]); | |
329 if(smk->frm_size) | |
330 av_free(smk->frm_size); | |
331 if(smk->frm_flags) | |
332 av_free(smk->frm_flags); | |
333 | |
334 return 0; | |
335 } | |
336 | |
1169 | 337 AVInputFormat smacker_demuxer = { |
1019 | 338 "smk", |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3399
diff
changeset
|
339 NULL_IF_CONFIG_SMALL("Smacker video"), |
1019 | 340 sizeof(SmackerContext), |
341 smacker_probe, | |
342 smacker_read_header, | |
343 smacker_read_packet, | |
344 smacker_read_close, | |
345 }; |