/src/ffmpeg/libavformat/rl2.c
Line | Count | Source |
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 |
24 | | * @file |
25 | | * @author Sascha Sommer (saschasommer@freenet.de) |
26 | | * @see http://wiki.multimedia.cx/index.php?title=RL2 |
27 | | * |
28 | | * extradata: |
29 | | * 2 byte le initial drawing offset within 320x200 viewport |
30 | | * 4 byte le number of used colors |
31 | | * 256 * 3 bytes rgb palette |
32 | | * optional background_frame |
33 | | */ |
34 | | |
35 | | #include <stdint.h> |
36 | | |
37 | | #include "libavutil/intreadwrite.h" |
38 | | #include "libavutil/mathematics.h" |
39 | | #include "libavutil/mem.h" |
40 | | #include "avformat.h" |
41 | | #include "demux.h" |
42 | | #include "internal.h" |
43 | | |
44 | 3.29k | #define EXTRADATA1_SIZE (6 + 256 * 3) ///< video base, clr, palette |
45 | | |
46 | 942k | #define FORM_TAG MKBETAG('F', 'O', 'R', 'M') |
47 | 10.5k | #define RLV2_TAG MKBETAG('R', 'L', 'V', '2') |
48 | 13.7k | #define RLV3_TAG MKBETAG('R', 'L', 'V', '3') |
49 | | |
50 | | typedef struct Rl2DemuxContext { |
51 | | unsigned int index_pos[2]; ///< indexes in the sample tables |
52 | | } Rl2DemuxContext; |
53 | | |
54 | | |
55 | | /** |
56 | | * check if the file is in rl2 format |
57 | | * @param p probe buffer |
58 | | * @return 0 when the probe buffer does not contain rl2 data, > 0 otherwise |
59 | | */ |
60 | | static int rl2_probe(const AVProbeData *p) |
61 | 942k | { |
62 | | |
63 | 942k | if(AV_RB32(&p->buf[0]) != FORM_TAG) |
64 | 932k | return 0; |
65 | | |
66 | 10.5k | if(AV_RB32(&p->buf[8]) != RLV2_TAG && |
67 | 10.4k | AV_RB32(&p->buf[8]) != RLV3_TAG) |
68 | 10.4k | return 0; |
69 | | |
70 | 122 | return AVPROBE_SCORE_MAX; |
71 | 10.5k | } |
72 | | |
73 | | /** |
74 | | * read rl2 header data and setup the avstreams |
75 | | * @param s demuxer context |
76 | | * @return 0 on success, AVERROR otherwise |
77 | | */ |
78 | | static av_cold int rl2_read_header(AVFormatContext *s) |
79 | 3.33k | { |
80 | 3.33k | AVIOContext *pb = s->pb; |
81 | 3.33k | AVStream *st; |
82 | 3.33k | unsigned int frame_count; |
83 | 3.33k | unsigned int audio_frame_counter = 0; |
84 | 3.33k | unsigned int video_frame_counter = 0; |
85 | 3.33k | unsigned int back_size; |
86 | 3.33k | unsigned short sound_rate; |
87 | 3.33k | unsigned short rate; |
88 | 3.33k | unsigned short channels; |
89 | 3.33k | unsigned short def_sound_size; |
90 | 3.33k | unsigned int signature; |
91 | 3.33k | unsigned int pts_den = 11025; /* video only case */ |
92 | 3.33k | unsigned int pts_num = 1103; |
93 | 3.33k | unsigned int* chunk_offset = NULL; |
94 | 3.33k | int* chunk_size = NULL; |
95 | 3.33k | int* audio_size = NULL; |
96 | 3.33k | int i; |
97 | 3.33k | int ret = 0; |
98 | | |
99 | 3.33k | avio_skip(pb,4); /* skip FORM tag */ |
100 | 3.33k | back_size = avio_rl32(pb); /**< get size of the background frame */ |
101 | 3.33k | signature = avio_rb32(pb); |
102 | 3.33k | avio_skip(pb, 4); /* data size */ |
103 | 3.33k | frame_count = avio_rl32(pb); |
104 | | |
105 | | /* disallow back_sizes and frame_counts that may lead to overflows later */ |
106 | 3.33k | if(back_size > INT_MAX/2 || frame_count > INT_MAX / sizeof(uint32_t)) |
107 | 45 | return AVERROR_INVALIDDATA; |
108 | | |
109 | 3.29k | avio_skip(pb, 2); /* encoding method */ |
110 | 3.29k | sound_rate = avio_rl16(pb); |
111 | 3.29k | rate = avio_rl16(pb); |
112 | 3.29k | channels = avio_rl16(pb); |
113 | 3.29k | def_sound_size = avio_rl16(pb); |
114 | | |
115 | | /** setup video stream */ |
116 | 3.29k | st = avformat_new_stream(s, NULL); |
117 | 3.29k | if(!st) |
118 | 0 | return AVERROR(ENOMEM); |
119 | | |
120 | 3.29k | st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; |
121 | 3.29k | st->codecpar->codec_id = AV_CODEC_ID_RL2; |
122 | 3.29k | st->codecpar->codec_tag = 0; /* no fourcc */ |
123 | 3.29k | st->codecpar->width = 320; |
124 | 3.29k | st->codecpar->height = 200; |
125 | | |
126 | | /** allocate and fill extradata */ |
127 | 3.29k | st->codecpar->extradata_size = EXTRADATA1_SIZE; |
128 | | |
129 | 3.29k | if(signature == RLV3_TAG && back_size > 0) |
130 | 163 | st->codecpar->extradata_size += back_size; |
131 | | |
132 | 3.29k | ret = ff_get_extradata(s, st->codecpar, pb, st->codecpar->extradata_size); |
133 | 3.29k | if (ret < 0) |
134 | 412 | return ret; |
135 | | |
136 | | /** setup audio stream if present */ |
137 | 2.88k | if(sound_rate){ |
138 | 2.57k | if (!channels || channels > 42) { |
139 | 22 | av_log(s, AV_LOG_ERROR, "Invalid number of channels: %d\n", channels); |
140 | 22 | return AVERROR_INVALIDDATA; |
141 | 22 | } |
142 | | |
143 | 2.55k | pts_num = def_sound_size; |
144 | 2.55k | pts_den = rate; |
145 | | |
146 | 2.55k | st = avformat_new_stream(s, NULL); |
147 | 2.55k | if (!st) |
148 | 0 | return AVERROR(ENOMEM); |
149 | 2.55k | st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; |
150 | 2.55k | st->codecpar->codec_id = AV_CODEC_ID_PCM_U8; |
151 | 2.55k | st->codecpar->codec_tag = 1; |
152 | 2.55k | st->codecpar->ch_layout.nb_channels = channels; |
153 | 2.55k | st->codecpar->bits_per_coded_sample = 8; |
154 | 2.55k | st->codecpar->sample_rate = rate; |
155 | 2.55k | st->codecpar->bit_rate = channels * st->codecpar->sample_rate * |
156 | 2.55k | st->codecpar->bits_per_coded_sample; |
157 | 2.55k | st->codecpar->block_align = channels * |
158 | 2.55k | st->codecpar->bits_per_coded_sample / 8; |
159 | 2.55k | avpriv_set_pts_info(st,32,1,rate); |
160 | 2.55k | } |
161 | | |
162 | 2.86k | avpriv_set_pts_info(s->streams[0], 32, pts_num, pts_den); |
163 | | |
164 | 2.86k | chunk_size = av_malloc(frame_count * sizeof(uint32_t)); |
165 | 2.86k | audio_size = av_malloc(frame_count * sizeof(uint32_t)); |
166 | 2.86k | chunk_offset = av_malloc(frame_count * sizeof(uint32_t)); |
167 | | |
168 | 2.86k | if(!chunk_size || !audio_size || !chunk_offset){ |
169 | 0 | av_free(chunk_size); |
170 | 0 | av_free(audio_size); |
171 | 0 | av_free(chunk_offset); |
172 | 0 | return AVERROR(ENOMEM); |
173 | 0 | } |
174 | | |
175 | | /** read offset and size tables */ |
176 | 3.46M | for(i=0; i < frame_count;i++) { |
177 | 3.46M | if (avio_feof(pb)) { |
178 | 66 | ret = AVERROR_INVALIDDATA; |
179 | 66 | goto end; |
180 | 66 | } |
181 | 3.46M | chunk_size[i] = avio_rl32(pb); |
182 | 3.46M | } |
183 | 3.30M | for(i=0; i < frame_count;i++) { |
184 | 3.30M | if (avio_feof(pb)) { |
185 | 41 | ret = AVERROR_INVALIDDATA; |
186 | 41 | goto end; |
187 | 41 | } |
188 | 3.30M | chunk_offset[i] = avio_rl32(pb); |
189 | 3.30M | } |
190 | 2.87M | for(i=0; i < frame_count;i++) { |
191 | 2.87M | if (avio_feof(pb)) { |
192 | 39 | ret = AVERROR_INVALIDDATA; |
193 | 39 | goto end; |
194 | 39 | } |
195 | 2.87M | audio_size[i] = avio_rl32(pb) & 0xFFFF; |
196 | 2.87M | } |
197 | | |
198 | | /** build the sample index */ |
199 | 2.66M | for(i=0;i<frame_count;i++){ |
200 | 2.66M | if(chunk_size[i] < 0 || audio_size[i] > chunk_size[i]){ |
201 | 109 | ret = AVERROR_INVALIDDATA; |
202 | 109 | break; |
203 | 109 | } |
204 | | |
205 | 2.66M | if(sound_rate && audio_size[i]){ |
206 | 857k | av_add_index_entry(s->streams[1], chunk_offset[i], |
207 | 857k | audio_frame_counter,audio_size[i], 0, AVINDEX_KEYFRAME); |
208 | 857k | audio_frame_counter += audio_size[i] / channels; |
209 | 857k | } |
210 | 2.66M | av_add_index_entry(s->streams[0], chunk_offset[i] + audio_size[i], |
211 | 2.66M | video_frame_counter,chunk_size[i]-audio_size[i],0,AVINDEX_KEYFRAME); |
212 | 2.66M | ++video_frame_counter; |
213 | 2.66M | } |
214 | | |
215 | 2.86k | end: |
216 | 2.86k | av_free(chunk_size); |
217 | 2.86k | av_free(audio_size); |
218 | 2.86k | av_free(chunk_offset); |
219 | | |
220 | 2.86k | return ret; |
221 | 2.71k | } |
222 | | |
223 | | /** |
224 | | * read a single audio or video packet |
225 | | * @param s demuxer context |
226 | | * @param pkt the packet to be filled |
227 | | * @return 0 on success, AVERROR otherwise |
228 | | */ |
229 | | static int rl2_read_packet(AVFormatContext *s, |
230 | | AVPacket *pkt) |
231 | 678k | { |
232 | 678k | Rl2DemuxContext *rl2 = s->priv_data; |
233 | 678k | AVIOContext *pb = s->pb; |
234 | 678k | AVIndexEntry *sample = NULL; |
235 | 678k | int i; |
236 | 678k | int ret = 0; |
237 | 678k | int stream_id = -1; |
238 | 678k | int64_t pos = INT64_MAX; |
239 | | |
240 | | /** check if there is a valid video or audio entry that can be used */ |
241 | 2.03M | for(i=0; i<s->nb_streams; i++){ |
242 | 1.35M | const FFStream *const sti = ffstream(s->streams[i]); |
243 | 1.35M | if (rl2->index_pos[i] < sti->nb_index_entries |
244 | 1.01M | && sti->index_entries[ rl2->index_pos[i] ].pos < pos) { |
245 | 727k | sample = &sti->index_entries[ rl2->index_pos[i] ]; |
246 | 727k | pos= sample->pos; |
247 | 727k | stream_id= i; |
248 | 727k | } |
249 | 1.35M | } |
250 | | |
251 | 678k | if(stream_id == -1) |
252 | 2.53k | return AVERROR_EOF; |
253 | | |
254 | 675k | ++rl2->index_pos[stream_id]; |
255 | | |
256 | | /** position the stream (will probably be there anyway) */ |
257 | 675k | avio_seek(pb, sample->pos, SEEK_SET); |
258 | | |
259 | | /** fill the packet */ |
260 | 675k | ret = av_get_packet(pb, pkt, sample->size); |
261 | 675k | if(ret != sample->size){ |
262 | 2.30k | return AVERROR_INVALIDDATA; |
263 | 2.30k | } |
264 | | |
265 | 673k | pkt->stream_index = stream_id; |
266 | 673k | pkt->pts = sample->timestamp; |
267 | | |
268 | 673k | return ret; |
269 | 675k | } |
270 | | |
271 | | /** |
272 | | * seek to a new timestamp |
273 | | * @param s demuxer context |
274 | | * @param stream_index index of the stream that should be seeked |
275 | | * @param timestamp wanted timestamp |
276 | | * @param flags direction and seeking mode |
277 | | * @return 0 on success, -1 otherwise |
278 | | */ |
279 | | static int rl2_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) |
280 | 0 | { |
281 | 0 | AVStream *st = s->streams[stream_index]; |
282 | 0 | Rl2DemuxContext *rl2 = s->priv_data; |
283 | 0 | int i; |
284 | 0 | int index = av_index_search_timestamp(st, timestamp, flags); |
285 | 0 | if(index < 0) |
286 | 0 | return -1; |
287 | | |
288 | 0 | rl2->index_pos[stream_index] = index; |
289 | 0 | timestamp = ffstream(st)->index_entries[index].timestamp; |
290 | |
|
291 | 0 | for(i=0; i < s->nb_streams; i++){ |
292 | 0 | AVStream *st2 = s->streams[i]; |
293 | 0 | index = av_index_search_timestamp(st2, |
294 | 0 | av_rescale_q(timestamp, st->time_base, st2->time_base), |
295 | 0 | flags | AVSEEK_FLAG_BACKWARD); |
296 | |
|
297 | 0 | if(index < 0) |
298 | 0 | index = 0; |
299 | |
|
300 | 0 | rl2->index_pos[i] = index; |
301 | 0 | } |
302 | |
|
303 | 0 | return 0; |
304 | 0 | } |
305 | | |
306 | | const FFInputFormat ff_rl2_demuxer = { |
307 | | .p.name = "rl2", |
308 | | .p.long_name = NULL_IF_CONFIG_SMALL("RL2"), |
309 | | .priv_data_size = sizeof(Rl2DemuxContext), |
310 | | .read_probe = rl2_probe, |
311 | | .read_header = rl2_read_header, |
312 | | .read_packet = rl2_read_packet, |
313 | | .read_seek = rl2_read_seek, |
314 | | }; |