Mercurial > libavformat.hg
annotate rl2.c @ 6296:7e7f9248ec87 libavformat
rtpdec_asf: Handle RTSP-MS packet splitting
author | mstorsjo |
---|---|
date | Wed, 21 Jul 2010 17:17:35 +0000 |
parents | 178de7695c6c |
children | 29171d6af13b |
rev | line source |
---|---|
3172 | 1 /* |
2 * RL2 Format Demuxer | |
3 * Copyright (c) 2008 Sascha Sommer (saschasommer@freenet.de) | |
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 /** | |
23 * RL2 file demuxer | |
5969
178de7695c6c
Remove explicit filename from Doxygen @file commands.
diego
parents:
5910
diff
changeset
|
24 * @file |
3172 | 25 * @author Sascha Sommer (saschasommer@freenet.de) |
26 * For more information regarding the RL2 file format, visit: | |
27 * http://wiki.multimedia.cx/index.php?title=RL2 | |
28 * | |
29 * extradata: | |
30 * 2 byte le initial drawing offset within 320x200 viewport | |
31 * 4 byte le number of used colors | |
32 * 256 * 3 bytes rgb palette | |
33 * optional background_frame | |
34 */ | |
35 | |
4201
7d2f3f1b68d8
Fix build: Add intreadwrite.h and bswap.h #includes where necessary.
diego
parents:
3908
diff
changeset
|
36 #include "libavutil/intreadwrite.h" |
3172 | 37 #include "avformat.h" |
38 | |
39 #define EXTRADATA1_SIZE (6 + 256 * 3) ///< video base, clr, palette | |
40 | |
41 #define FORM_TAG MKBETAG('F', 'O', 'R', 'M') | |
42 #define RLV2_TAG MKBETAG('R', 'L', 'V', '2') | |
43 #define RLV3_TAG MKBETAG('R', 'L', 'V', '3') | |
44 | |
45 typedef struct Rl2DemuxContext { | |
3365 | 46 unsigned int index_pos[2]; ///< indexes in the sample tables |
3172 | 47 } Rl2DemuxContext; |
48 | |
49 | |
50 /** | |
51 * check if the file is in rl2 format | |
52 * @param p probe buffer | |
53 * @return 0 when the probe buffer does not contain rl2 data, > 0 otherwise | |
54 */ | |
55 static int rl2_probe(AVProbeData *p) | |
56 { | |
57 | |
58 if(AV_RB32(&p->buf[0]) != FORM_TAG) | |
59 return 0; | |
60 | |
61 if(AV_RB32(&p->buf[8]) != RLV2_TAG && | |
62 AV_RB32(&p->buf[8]) != RLV3_TAG) | |
63 return 0; | |
64 | |
65 return AVPROBE_SCORE_MAX; | |
66 } | |
67 | |
68 /** | |
69 * read rl2 header data and setup the avstreams | |
70 * @param s demuxer context | |
71 * @param ap format parameters | |
72 * @return 0 on success, AVERROR otherwise | |
73 */ | |
74 static av_cold int rl2_read_header(AVFormatContext *s, | |
75 AVFormatParameters *ap) | |
76 { | |
77 ByteIOContext *pb = s->pb; | |
78 AVStream *st; | |
79 unsigned int frame_count; | |
80 unsigned int audio_frame_counter = 0; | |
81 unsigned int video_frame_counter = 0; | |
82 unsigned int back_size; | |
83 int data_size; | |
84 unsigned short encoding_method; | |
85 unsigned short sound_rate; | |
86 unsigned short rate; | |
87 unsigned short channels; | |
88 unsigned short def_sound_size; | |
89 unsigned int signature; | |
90 unsigned int pts_den = 11025; /* video only case */ | |
91 unsigned int pts_num = 1103; | |
92 unsigned int* chunk_offset = NULL; | |
93 int* chunk_size = NULL; | |
94 int* audio_size = NULL; | |
95 int i; | |
96 int ret = 0; | |
97 | |
98 url_fskip(pb,4); /* skip FORM tag */ | |
99 back_size = get_le32(pb); /** get size of the background frame */ | |
100 signature = get_be32(pb); | |
101 data_size = get_be32(pb); | |
102 frame_count = get_le32(pb); | |
103 | |
104 /* disallow back_sizes and frame_counts that may lead to overflows later */ | |
105 if(back_size > INT_MAX/2 || frame_count > INT_MAX / sizeof(uint32_t)) | |
106 return AVERROR_INVALIDDATA; | |
107 | |
108 encoding_method = get_le16(pb); | |
109 sound_rate = get_le16(pb); | |
110 rate = get_le16(pb); | |
111 channels = get_le16(pb); | |
112 def_sound_size = get_le16(pb); | |
113 | |
114 /** setup video stream */ | |
115 st = av_new_stream(s, 0); | |
116 if(!st) | |
117 return AVERROR(ENOMEM); | |
118 | |
5910
536e5527c1e0
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
4464
diff
changeset
|
119 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; |
3172 | 120 st->codec->codec_id = CODEC_ID_RL2; |
121 st->codec->codec_tag = 0; /* no fourcc */ | |
122 st->codec->width = 320; | |
123 st->codec->height = 200; | |
124 | |
125 /** allocate and fill extradata */ | |
126 st->codec->extradata_size = EXTRADATA1_SIZE; | |
127 | |
128 if(signature == RLV3_TAG && back_size > 0) | |
129 st->codec->extradata_size += back_size; | |
130 | |
131 st->codec->extradata = av_mallocz(st->codec->extradata_size + | |
132 FF_INPUT_BUFFER_PADDING_SIZE); | |
133 if(!st->codec->extradata) | |
134 return AVERROR(ENOMEM); | |
135 | |
136 if(get_buffer(pb,st->codec->extradata,st->codec->extradata_size) != | |
137 st->codec->extradata_size) | |
138 return AVERROR(EIO); | |
139 | |
140 /** setup audio stream if present */ | |
141 if(sound_rate){ | |
142 pts_num = def_sound_size; | |
143 pts_den = rate; | |
144 | |
145 st = av_new_stream(s, 0); | |
146 if (!st) | |
147 return AVERROR(ENOMEM); | |
5910
536e5527c1e0
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
4464
diff
changeset
|
148 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
3172 | 149 st->codec->codec_id = CODEC_ID_PCM_U8; |
150 st->codec->codec_tag = 1; | |
151 st->codec->channels = channels; | |
3908
1d3d17de20ba
Bump Major version, this commit is almost just renaming bits_per_sample to
michael
parents:
3424
diff
changeset
|
152 st->codec->bits_per_coded_sample = 8; |
3172 | 153 st->codec->sample_rate = rate; |
154 st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * | |
3908
1d3d17de20ba
Bump Major version, this commit is almost just renaming bits_per_sample to
michael
parents:
3424
diff
changeset
|
155 st->codec->bits_per_coded_sample; |
3172 | 156 st->codec->block_align = st->codec->channels * |
3908
1d3d17de20ba
Bump Major version, this commit is almost just renaming bits_per_sample to
michael
parents:
3424
diff
changeset
|
157 st->codec->bits_per_coded_sample / 8; |
3172 | 158 av_set_pts_info(st,32,1,rate); |
159 } | |
160 | |
161 av_set_pts_info(s->streams[0], 32, pts_num, pts_den); | |
162 | |
163 chunk_size = av_malloc(frame_count * sizeof(uint32_t)); | |
164 audio_size = av_malloc(frame_count * sizeof(uint32_t)); | |
165 chunk_offset = av_malloc(frame_count * sizeof(uint32_t)); | |
166 | |
167 if(!chunk_size || !audio_size || !chunk_offset){ | |
168 av_free(chunk_size); | |
169 av_free(audio_size); | |
170 av_free(chunk_offset); | |
171 return AVERROR(ENOMEM); | |
172 } | |
173 | |
174 /** read offset and size tables */ | |
175 for(i=0; i < frame_count;i++) | |
176 chunk_size[i] = get_le32(pb); | |
177 for(i=0; i < frame_count;i++) | |
178 chunk_offset[i] = get_le32(pb); | |
179 for(i=0; i < frame_count;i++) | |
180 audio_size[i] = get_le32(pb) & 0xFFFF; | |
181 | |
182 /** build the sample index */ | |
183 for(i=0;i<frame_count;i++){ | |
184 if(chunk_size[i] < 0 || audio_size[i] > chunk_size[i]){ | |
185 ret = AVERROR_INVALIDDATA; | |
186 break; | |
187 } | |
188 | |
189 if(sound_rate && audio_size[i]){ | |
190 av_add_index_entry(s->streams[1], chunk_offset[i], | |
191 audio_frame_counter,audio_size[i], 0, AVINDEX_KEYFRAME); | |
192 audio_frame_counter += audio_size[i] / channels; | |
193 } | |
194 av_add_index_entry(s->streams[0], chunk_offset[i] + audio_size[i], | |
195 video_frame_counter,chunk_size[i]-audio_size[i],0,AVINDEX_KEYFRAME); | |
196 ++video_frame_counter; | |
197 } | |
198 | |
199 | |
200 av_free(chunk_size); | |
201 av_free(audio_size); | |
202 av_free(chunk_offset); | |
203 | |
204 return ret; | |
205 } | |
206 | |
207 /** | |
208 * read a single audio or video packet | |
209 * @param s demuxer context | |
210 * @param pkt the packet to be filled | |
211 * @return 0 on success, AVERROR otherwise | |
212 */ | |
213 static int rl2_read_packet(AVFormatContext *s, | |
214 AVPacket *pkt) | |
215 { | |
216 Rl2DemuxContext *rl2 = s->priv_data; | |
217 ByteIOContext *pb = s->pb; | |
218 AVIndexEntry *sample = NULL; | |
219 int i; | |
220 int ret = 0; | |
221 int stream_id = -1; | |
222 int64_t pos = INT64_MAX; | |
223 | |
224 /** check if there is a valid video or audio entry that can be used */ | |
225 for(i=0; i<s->nb_streams; i++){ | |
226 if(rl2->index_pos[i] < s->streams[i]->nb_index_entries | |
227 && s->streams[i]->index_entries[ rl2->index_pos[i] ].pos < pos){ | |
228 sample = &s->streams[i]->index_entries[ rl2->index_pos[i] ]; | |
229 pos= sample->pos; | |
230 stream_id= i; | |
231 } | |
232 } | |
233 | |
234 if(stream_id == -1) | |
235 return AVERROR(EIO); | |
236 | |
237 ++rl2->index_pos[stream_id]; | |
238 | |
239 /** position the stream (will probably be there anyway) */ | |
240 url_fseek(pb, sample->pos, SEEK_SET); | |
241 | |
242 /** fill the packet */ | |
243 ret = av_get_packet(pb, pkt, sample->size); | |
244 if(ret != sample->size){ | |
245 av_free_packet(pkt); | |
246 return AVERROR(EIO); | |
247 } | |
248 | |
249 pkt->stream_index = stream_id; | |
250 pkt->pts = sample->timestamp; | |
251 | |
252 return ret; | |
253 } | |
254 | |
255 /** | |
256 * seek to a new timestamp | |
257 * @param s demuxer context | |
258 * @param stream_index index of the stream that should be seeked | |
259 * @param timestamp wanted timestamp | |
260 * @param flags direction and seeking mode | |
261 * @return 0 on success, -1 otherwise | |
262 */ | |
263 static int rl2_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) | |
264 { | |
265 AVStream *st = s->streams[stream_index]; | |
266 Rl2DemuxContext *rl2 = s->priv_data; | |
267 int i; | |
268 int index = av_index_search_timestamp(st, timestamp, flags); | |
269 if(index < 0) | |
270 return -1; | |
271 | |
272 rl2->index_pos[stream_index] = index; | |
273 timestamp = st->index_entries[index].timestamp; | |
274 | |
275 for(i=0; i < s->nb_streams; i++){ | |
276 AVStream *st2 = s->streams[i]; | |
277 index = av_index_search_timestamp(st2, | |
278 av_rescale_q(timestamp, st->time_base, st2->time_base), | |
279 flags | AVSEEK_FLAG_BACKWARD); | |
280 | |
281 if(index < 0) | |
282 index = 0; | |
283 | |
284 rl2->index_pos[i] = index; | |
285 } | |
286 | |
287 return 0; | |
288 } | |
289 | |
290 AVInputFormat rl2_demuxer = { | |
291 "rl2", | |
4464 | 292 NULL_IF_CONFIG_SMALL("RL2 format"), |
3172 | 293 sizeof(Rl2DemuxContext), |
294 rl2_probe, | |
295 rl2_read_header, | |
296 rl2_read_packet, | |
297 NULL, | |
298 rl2_read_seek, | |
299 }; | |
300 |