Mercurial > libavformat.hg
annotate smacker.c @ 5330:936a03bbd757 libavformat
Suppress ?params in the rtsp uri
Right now rtsp demuxer receives it's ffmpeg specific params encoded in the url
That made the server receiving requests with the url ending with "?udp",
"?multicast" and "?tcp". That may or may not cause problems to servers with
overly strict or overly simple uri parsers
Patch from Armand Bendanan (name.surnameATfreeDOTfr)
author | lu_zero |
---|---|
date | Sat, 24 Oct 2009 15:18:21 +0000 |
parents | 2da42f33de42 |
children | 942ca859a587 |
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 |
4251
77e0c7511d41
cosmetics: Remove pointless period after copyright statement non-sentences.
diego
parents:
4201
diff
changeset
|
3 * Copyright (c) 2006 Konstantin Shishkov |
1019 | 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" |
4201
7d2f3f1b68d8
Fix build: Add intreadwrite.h and bswap.h #includes where necessary.
diego
parents:
3973
diff
changeset
|
27 #include "libavutil/intreadwrite.h" |
1019 | 28 #include "avformat.h" |
29 | |
30 #define SMACKER_PAL 0x01 | |
2404 | 31 #define SMACKER_FLAG_RING_FRAME 0x01 |
1019 | 32 |
33 enum SAudFlags { | |
34 SMK_AUD_PACKED = 0x80000000, | |
35 SMK_AUD_16BITS = 0x20000000, | |
36 SMK_AUD_STEREO = 0x10000000, | |
37 SMK_AUD_BINKAUD = 0x08000000, | |
38 SMK_AUD_USEDCT = 0x04000000 | |
39 }; | |
40 | |
41 typedef struct SmackerContext { | |
42 /* Smacker file header */ | |
43 uint32_t magic; | |
44 uint32_t width, height; | |
45 uint32_t frames; | |
46 int pts_inc; | |
47 uint32_t flags; | |
48 uint32_t audio[7]; | |
49 uint32_t treesize; | |
50 uint32_t mmap_size, mclr_size, full_size, type_size; | |
51 uint32_t rates[7]; | |
52 uint32_t pad; | |
53 /* frame info */ | |
54 uint32_t *frm_size; | |
55 uint8_t *frm_flags; | |
56 /* internal variables */ | |
57 int cur_frame; | |
58 int is_ver4; | |
59 int64_t cur_pts; | |
60 /* current frame for demuxing */ | |
61 uint8_t pal[768]; | |
62 int indexes[7]; | |
63 int videoindex; | |
64 uint8_t *bufs[7]; | |
65 int buf_sizes[7]; | |
66 int stream_id[7]; | |
67 int curstream; | |
3973
549a09cf23fe
Remove offset_t typedef and use int64_t directly instead.
diego
parents:
3908
diff
changeset
|
68 int64_t nextpos; |
1090 | 69 int64_t aud_pts[7]; |
1019 | 70 } SmackerContext; |
71 | |
72 typedef struct SmackerFrame { | |
73 int64_t pts; | |
74 int stream; | |
75 } SmackerFrame; | |
76 | |
77 /* palette used in Smacker */ | |
78 static const uint8_t smk_pal[64] = { | |
79 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C, | |
80 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C, | |
81 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D, | |
82 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, | |
83 0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E, | |
84 0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE, | |
85 0xC3, 0xC7, 0xCB, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF, | |
86 0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF | |
87 }; | |
88 | |
89 | |
90 static int smacker_probe(AVProbeData *p) | |
91 { | |
92 if(p->buf[0] == 'S' && p->buf[1] == 'M' && p->buf[2] == 'K' | |
93 && (p->buf[3] == '2' || p->buf[3] == '4')) | |
94 return AVPROBE_SCORE_MAX; | |
95 else | |
96 return 0; | |
97 } | |
98 | |
99 static int smacker_read_header(AVFormatContext *s, AVFormatParameters *ap) | |
100 { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
101 ByteIOContext *pb = s->pb; |
2006 | 102 SmackerContext *smk = s->priv_data; |
1019 | 103 AVStream *st, *ast[7]; |
104 int i, ret; | |
105 int tbase; | |
106 | |
107 /* read and check header */ | |
108 smk->magic = get_le32(pb); | |
109 if (smk->magic != MKTAG('S', 'M', 'K', '2') && smk->magic != MKTAG('S', 'M', 'K', '4')) | |
110 return -1; | |
111 smk->width = get_le32(pb); | |
112 smk->height = get_le32(pb); | |
113 smk->frames = get_le32(pb); | |
114 smk->pts_inc = (int32_t)get_le32(pb); | |
115 smk->flags = get_le32(pb); | |
2404 | 116 if(smk->flags & SMACKER_FLAG_RING_FRAME) |
117 smk->frames++; | |
1019 | 118 for(i = 0; i < 7; i++) |
119 smk->audio[i] = get_le32(pb); | |
120 smk->treesize = get_le32(pb); | |
1079 | 121 |
122 if(smk->treesize >= UINT_MAX/4){ // smk->treesize + 16 must not overflow (this check is probably redundant) | |
123 av_log(s, AV_LOG_ERROR, "treesize too large\n"); | |
124 return -1; | |
125 } | |
126 | |
127 //FIXME remove extradata "rebuilding" | |
1019 | 128 smk->mmap_size = get_le32(pb); |
129 smk->mclr_size = get_le32(pb); | |
130 smk->full_size = get_le32(pb); | |
131 smk->type_size = get_le32(pb); | |
132 for(i = 0; i < 7; i++) | |
133 smk->rates[i] = get_le32(pb); | |
134 smk->pad = get_le32(pb); | |
135 /* setup data */ | |
136 if(smk->frames > 0xFFFFFF) { | |
137 av_log(s, AV_LOG_ERROR, "Too many frames: %i\n", smk->frames); | |
138 return -1; | |
139 } | |
140 smk->frm_size = av_malloc(smk->frames * 4); | |
141 smk->frm_flags = av_malloc(smk->frames); | |
142 | |
143 smk->is_ver4 = (smk->magic != MKTAG('S', 'M', 'K', '2')); | |
144 | |
145 /* read frame info */ | |
146 for(i = 0; i < smk->frames; i++) { | |
147 smk->frm_size[i] = get_le32(pb); | |
148 } | |
149 for(i = 0; i < smk->frames; i++) { | |
150 smk->frm_flags[i] = get_byte(pb); | |
151 } | |
152 | |
153 /* init video codec */ | |
154 st = av_new_stream(s, 0); | |
155 if (!st) | |
156 return -1; | |
157 smk->videoindex = st->index; | |
158 st->codec->width = smk->width; | |
159 st->codec->height = smk->height; | |
160 st->codec->pix_fmt = PIX_FMT_PAL8; | |
161 st->codec->codec_type = CODEC_TYPE_VIDEO; | |
162 st->codec->codec_id = CODEC_ID_SMACKVIDEO; | |
1089
0319672689ef
Now MPlayer should understand Smacker audio and video codecs.
kostya
parents:
1079
diff
changeset
|
163 st->codec->codec_tag = smk->magic; |
1019 | 164 /* Smacker uses 100000 as internal timebase */ |
165 if(smk->pts_inc < 0) | |
166 smk->pts_inc = -smk->pts_inc; | |
167 else | |
168 smk->pts_inc *= 100; | |
169 tbase = 100000; | |
170 av_reduce(&tbase, &smk->pts_inc, tbase, smk->pts_inc, (1UL<<31)-1); | |
171 av_set_pts_info(st, 33, smk->pts_inc, tbase); | |
172 /* handle possible audio streams */ | |
173 for(i = 0; i < 7; i++) { | |
174 smk->indexes[i] = -1; | |
175 if((smk->rates[i] & 0xFFFFFF) && !(smk->rates[i] & SMK_AUD_BINKAUD)){ | |
176 ast[i] = av_new_stream(s, 0); | |
177 smk->indexes[i] = ast[i]->index; | |
178 ast[i]->codec->codec_type = CODEC_TYPE_AUDIO; | |
179 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
|
180 ast[i]->codec->codec_tag = MKTAG('S', 'M', 'K', 'A'); |
1019 | 181 ast[i]->codec->channels = (smk->rates[i] & SMK_AUD_STEREO) ? 2 : 1; |
182 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
|
183 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
|
184 if(ast[i]->codec->bits_per_coded_sample == 16 && ast[i]->codec->codec_id == CODEC_ID_PCM_U8) |
1019 | 185 ast[i]->codec->codec_id = CODEC_ID_PCM_S16LE; |
4767
2da42f33de42
Make Smacker audio decoder output audio in original bit depth
kostya
parents:
4251
diff
changeset
|
186 ast[i]->codec->sample_fmt = ast[i]->codec->bits_per_coded_sample == 8 ? SAMPLE_FMT_U8 : SAMPLE_FMT_S16; |
1090 | 187 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
|
188 * ast[i]->codec->channels * ast[i]->codec->bits_per_coded_sample / 8); |
1019 | 189 } |
190 } | |
191 | |
192 | |
193 /* load trees to extradata, they will be unpacked by decoder */ | |
194 st->codec->extradata = av_malloc(smk->treesize + 16); | |
195 st->codec->extradata_size = smk->treesize + 16; | |
196 if(!st->codec->extradata){ | |
197 av_log(s, AV_LOG_ERROR, "Cannot allocate %i bytes of extradata\n", smk->treesize + 16); | |
198 av_free(smk->frm_size); | |
199 av_free(smk->frm_flags); | |
200 return -1; | |
201 } | |
202 ret = get_buffer(pb, st->codec->extradata + 16, st->codec->extradata_size - 16); | |
203 if(ret != st->codec->extradata_size - 16){ | |
204 av_free(smk->frm_size); | |
205 av_free(smk->frm_flags); | |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
206 return AVERROR(EIO); |
1019 | 207 } |
208 ((int32_t*)st->codec->extradata)[0] = le2me_32(smk->mmap_size); | |
209 ((int32_t*)st->codec->extradata)[1] = le2me_32(smk->mclr_size); | |
210 ((int32_t*)st->codec->extradata)[2] = le2me_32(smk->full_size); | |
211 ((int32_t*)st->codec->extradata)[3] = le2me_32(smk->type_size); | |
212 | |
213 smk->curstream = -1; | |
214 smk->nextpos = url_ftell(pb); | |
215 | |
216 return 0; | |
217 } | |
218 | |
219 | |
220 static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) | |
221 { | |
2006 | 222 SmackerContext *smk = s->priv_data; |
1019 | 223 int flags; |
224 int ret; | |
225 int i; | |
226 int frame_size = 0; | |
227 int palchange = 0; | |
228 int pos; | |
229 | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
230 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
|
231 return AVERROR(EIO); |
1019 | 232 |
233 /* if we demuxed all streams, pass another frame */ | |
234 if(smk->curstream < 0) { | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
235 url_fseek(s->pb, smk->nextpos, 0); |
1019 | 236 frame_size = smk->frm_size[smk->cur_frame] & (~3); |
237 flags = smk->frm_flags[smk->cur_frame]; | |
238 /* handle palette change event */ | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
239 pos = url_ftell(s->pb); |
1019 | 240 if(flags & SMACKER_PAL){ |
241 int size, sz, t, off, j, pos; | |
242 uint8_t *pal = smk->pal; | |
243 uint8_t oldpal[768]; | |
244 | |
245 memcpy(oldpal, pal, 768); | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
246 size = get_byte(s->pb); |
1019 | 247 size = size * 4 - 1; |
248 frame_size -= size; | |
249 frame_size--; | |
250 sz = 0; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
251 pos = url_ftell(s->pb) + size; |
1019 | 252 while(sz < 256){ |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
253 t = get_byte(s->pb); |
1019 | 254 if(t & 0x80){ /* skip palette entries */ |
255 sz += (t & 0x7F) + 1; | |
256 pal += ((t & 0x7F) + 1) * 3; | |
257 } else if(t & 0x40){ /* copy with offset */ | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
258 off = get_byte(s->pb) * 3; |
1019 | 259 j = (t & 0x3F) + 1; |
260 while(j-- && sz < 256) { | |
261 *pal++ = oldpal[off + 0]; | |
262 *pal++ = oldpal[off + 1]; | |
263 *pal++ = oldpal[off + 2]; | |
264 sz++; | |
265 off += 3; | |
266 } | |
267 } else { /* new entries */ | |
268 *pal++ = smk_pal[t]; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
269 *pal++ = smk_pal[get_byte(s->pb) & 0x3F]; |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
270 *pal++ = smk_pal[get_byte(s->pb) & 0x3F]; |
1019 | 271 sz++; |
272 } | |
273 } | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
274 url_fseek(s->pb, pos, 0); |
1019 | 275 palchange |= 1; |
276 } | |
277 flags >>= 1; | |
278 smk->curstream = -1; | |
279 /* if audio chunks are present, put them to stack and retrieve later */ | |
280 for(i = 0; i < 7; i++) { | |
281 if(flags & 1) { | |
282 int size; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
283 size = get_le32(s->pb) - 4; |
1019 | 284 frame_size -= size; |
285 frame_size -= 4; | |
286 smk->curstream++; | |
287 smk->bufs[smk->curstream] = av_realloc(smk->bufs[smk->curstream], size); | |
288 smk->buf_sizes[smk->curstream] = size; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
289 ret = get_buffer(s->pb, smk->bufs[smk->curstream], size); |
1019 | 290 if(ret != size) |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
291 return AVERROR(EIO); |
1019 | 292 smk->stream_id[smk->curstream] = smk->indexes[i]; |
293 } | |
294 flags >>= 1; | |
295 } | |
296 if (av_new_packet(pkt, frame_size + 768)) | |
2273
7eb456c4ed8a
Replace all occurrences of AVERROR_NOMEM with AVERROR(ENOMEM).
takis
parents:
2006
diff
changeset
|
297 return AVERROR(ENOMEM); |
1019 | 298 if(smk->frm_size[smk->cur_frame] & 1) |
299 palchange |= 2; | |
300 pkt->data[0] = palchange; | |
301 memcpy(pkt->data + 1, smk->pal, 768); | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
302 ret = get_buffer(s->pb, pkt->data + 769, frame_size); |
1019 | 303 if(ret != frame_size) |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
304 return AVERROR(EIO); |
1019 | 305 pkt->stream_index = smk->videoindex; |
306 pkt->size = ret + 769; | |
307 smk->cur_frame++; | |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2404
diff
changeset
|
308 smk->nextpos = url_ftell(s->pb); |
1019 | 309 } else { |
310 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
|
311 return AVERROR(ENOMEM); |
1019 | 312 memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]); |
313 pkt->size = smk->buf_sizes[smk->curstream]; | |
314 pkt->stream_index = smk->stream_id[smk->curstream]; | |
1090 | 315 pkt->pts = smk->aud_pts[smk->curstream]; |
1673 | 316 smk->aud_pts[smk->curstream] += AV_RL32(pkt->data); |
1019 | 317 smk->curstream--; |
318 } | |
319 | |
320 return 0; | |
321 } | |
322 | |
323 static int smacker_read_close(AVFormatContext *s) | |
324 { | |
2006 | 325 SmackerContext *smk = s->priv_data; |
1019 | 326 int i; |
327 | |
328 for(i = 0; i < 7; i++) | |
329 if(smk->bufs[i]) | |
330 av_free(smk->bufs[i]); | |
331 if(smk->frm_size) | |
332 av_free(smk->frm_size); | |
333 if(smk->frm_flags) | |
334 av_free(smk->frm_flags); | |
335 | |
336 return 0; | |
337 } | |
338 | |
1169 | 339 AVInputFormat smacker_demuxer = { |
1019 | 340 "smk", |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3399
diff
changeset
|
341 NULL_IF_CONFIG_SMALL("Smacker video"), |
1019 | 342 sizeof(SmackerContext), |
343 smacker_probe, | |
344 smacker_read_header, | |
345 smacker_read_packet, | |
346 smacker_read_close, | |
347 }; |