Mercurial > libavformat.hg
annotate rl2.c @ 6085:72c7c3d5c4e9 libavformat
matroskaenc: Mux clusters better
Start them on keyframes when reasonable, and delay writing audio packets
to help ensure that there's audio samples available for the first frame in
clusters.
Patch by James Zern <jzern at google>
author | conrad |
---|---|
date | Fri, 04 Jun 2010 22:40:50 +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 |