Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * "Real" compatible demuxer. |
||
3 | * Copyright (c) 2000, 2001 Fabrice Bellard |
||
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 | #include "libavutil/avassert.h" |
||
23 | #include "libavutil/avstring.h" |
||
24 | #include "libavutil/channel_layout.h" |
||
25 | #include "libavutil/internal.h" |
||
26 | #include "libavutil/intreadwrite.h" |
||
27 | #include "libavutil/dict.h" |
||
28 | #include "avformat.h" |
||
29 | #include "avio_internal.h" |
||
30 | #include "internal.h" |
||
31 | #include "rmsipr.h" |
||
32 | #include "rm.h" |
||
33 | |||
34 | #define DEINT_ID_GENR MKTAG('g', 'e', 'n', 'r') ///< interleaving for Cooker/ATRAC |
||
35 | #define DEINT_ID_INT0 MKTAG('I', 'n', 't', '0') ///< no interleaving needed |
||
36 | #define DEINT_ID_INT4 MKTAG('I', 'n', 't', '4') ///< interleaving for 28.8 |
||
37 | #define DEINT_ID_SIPR MKTAG('s', 'i', 'p', 'r') ///< interleaving for Sipro |
||
38 | #define DEINT_ID_VBRF MKTAG('v', 'b', 'r', 'f') ///< VBR case for AAC |
||
39 | #define DEINT_ID_VBRS MKTAG('v', 'b', 'r', 's') ///< VBR case for AAC |
||
40 | |||
41 | struct RMStream { |
||
42 | AVPacket pkt; ///< place to store merged video frame / reordered audio data |
||
43 | int videobufsize; ///< current assembled frame size |
||
44 | int videobufpos; ///< position for the next slice in the video buffer |
||
45 | int curpic_num; ///< picture number of current frame |
||
46 | int cur_slice, slices; |
||
47 | int64_t pktpos; ///< first slice position in file |
||
48 | /// Audio descrambling matrix parameters |
||
49 | int64_t audiotimestamp; ///< Audio packet timestamp |
||
50 | int sub_packet_cnt; // Subpacket counter, used while reading |
||
51 | int sub_packet_size, sub_packet_h, coded_framesize; ///< Descrambling parameters from container |
||
52 | int audio_framesize; /// Audio frame size from container |
||
53 | int sub_packet_lengths[16]; /// Length of each subpacket |
||
54 | int32_t deint_id; ///< deinterleaver used in audio stream |
||
55 | }; |
||
56 | |||
57 | typedef struct { |
||
58 | int nb_packets; |
||
59 | int old_format; |
||
60 | int current_stream; |
||
61 | int remaining_len; |
||
62 | int audio_stream_num; ///< Stream number for audio packets |
||
63 | int audio_pkt_cnt; ///< Output packet counter |
||
64 | } RMDemuxContext; |
||
65 | |||
66 | static inline void get_strl(AVIOContext *pb, char *buf, int buf_size, int len) |
||
67 | { |
||
68 | int i; |
||
69 | char *q, r; |
||
70 | |||
71 | q = buf; |
||
72 | for(i=0;i |
||
73 | r = avio_r8(pb); |
||
74 | if (i < buf_size - 1) |
||
75 | *q++ = r; |
||
76 | } |
||
77 | if (buf_size > 0) *q = '\0'; |
||
78 | } |
||
79 | |||
80 | static void get_str8(AVIOContext *pb, char *buf, int buf_size) |
||
81 | { |
||
82 | get_strl(pb, buf, buf_size, avio_r8(pb)); |
||
83 | } |
||
84 | |||
85 | static int rm_read_extradata(AVIOContext *pb, AVCodecContext *avctx, unsigned size) |
||
86 | { |
||
87 | if (size >= 1<<24) |
||
88 | return -1; |
||
89 | if (ff_alloc_extradata(avctx, size)) |
||
90 | return AVERROR(ENOMEM); |
||
91 | avctx->extradata_size = avio_read(pb, avctx->extradata, size); |
||
92 | if (avctx->extradata_size != size) |
||
93 | return AVERROR(EIO); |
||
94 | return 0; |
||
95 | } |
||
96 | |||
97 | static void rm_read_metadata(AVFormatContext *s, AVIOContext *pb, int wide) |
||
98 | { |
||
99 | char buf[1024]; |
||
100 | int i; |
||
101 | |||
102 | for (i=0; i |
||
103 | int len = wide ? avio_rb16(pb) : avio_r8(pb); |
||
104 | get_strl(pb, buf, sizeof(buf), len); |
||
105 | av_dict_set(&s->metadata, ff_rm_metadata[i], buf, 0); |
||
106 | } |
||
107 | } |
||
108 | |||
109 | RMStream *ff_rm_alloc_rmstream (void) |
||
110 | { |
||
111 | RMStream *rms = av_mallocz(sizeof(RMStream)); |
||
112 | rms->curpic_num = -1; |
||
113 | return rms; |
||
114 | } |
||
115 | |||
116 | void ff_rm_free_rmstream (RMStream *rms) |
||
117 | { |
||
118 | av_free_packet(&rms->pkt); |
||
119 | } |
||
120 | |||
121 | static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, |
||
122 | AVStream *st, RMStream *ast, int read_all) |
||
123 | { |
||
124 | char buf[256]; |
||
125 | uint32_t version; |
||
126 | int ret; |
||
127 | |||
128 | /* ra type header */ |
||
129 | version = avio_rb16(pb); /* version */ |
||
130 | if (version == 3) { |
||
131 | unsigned bytes_per_minute; |
||
132 | int header_size = avio_rb16(pb); |
||
133 | int64_t startpos = avio_tell(pb); |
||
134 | avio_skip(pb, 8); |
||
135 | bytes_per_minute = avio_rb16(pb); |
||
136 | avio_skip(pb, 4); |
||
137 | rm_read_metadata(s, pb, 0); |
||
138 | if ((startpos + header_size) >= avio_tell(pb) + 2) { |
||
139 | // fourcc (should always be "lpcJ") |
||
140 | avio_r8(pb); |
||
141 | get_str8(pb, buf, sizeof(buf)); |
||
142 | } |
||
143 | // Skip extra header crap (this should never happen) |
||
144 | if ((startpos + header_size) > avio_tell(pb)) |
||
145 | avio_skip(pb, header_size + startpos - avio_tell(pb)); |
||
146 | if (bytes_per_minute) |
||
147 | st->codec->bit_rate = 8LL * bytes_per_minute / 60; |
||
148 | st->codec->sample_rate = 8000; |
||
149 | st->codec->channels = 1; |
||
150 | st->codec->channel_layout = AV_CH_LAYOUT_MONO; |
||
151 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
||
152 | st->codec->codec_id = AV_CODEC_ID_RA_144; |
||
153 | ast->deint_id = DEINT_ID_INT0; |
||
154 | } else { |
||
155 | int flavor, sub_packet_h, coded_framesize, sub_packet_size; |
||
156 | int codecdata_length; |
||
157 | unsigned bytes_per_minute; |
||
158 | /* old version (4) */ |
||
159 | avio_skip(pb, 2); /* unused */ |
||
160 | avio_rb32(pb); /* .ra4 */ |
||
161 | avio_rb32(pb); /* data size */ |
||
162 | avio_rb16(pb); /* version2 */ |
||
163 | avio_rb32(pb); /* header size */ |
||
164 | flavor= avio_rb16(pb); /* add codec info / flavor */ |
||
165 | ast->coded_framesize = coded_framesize = avio_rb32(pb); /* coded frame size */ |
||
166 | avio_rb32(pb); /* ??? */ |
||
167 | bytes_per_minute = avio_rb32(pb); |
||
168 | if (version == 4) { |
||
169 | if (bytes_per_minute) |
||
170 | st->codec->bit_rate = 8LL * bytes_per_minute / 60; |
||
171 | } |
||
172 | avio_rb32(pb); /* ??? */ |
||
173 | ast->sub_packet_h = sub_packet_h = avio_rb16(pb); /* 1 */ |
||
174 | st->codec->block_align= avio_rb16(pb); /* frame size */ |
||
175 | ast->sub_packet_size = sub_packet_size = avio_rb16(pb); /* sub packet size */ |
||
176 | avio_rb16(pb); /* ??? */ |
||
177 | if (version == 5) { |
||
178 | avio_rb16(pb); avio_rb16(pb); avio_rb16(pb); |
||
179 | } |
||
180 | st->codec->sample_rate = avio_rb16(pb); |
||
181 | avio_rb32(pb); |
||
182 | st->codec->channels = avio_rb16(pb); |
||
183 | if (version == 5) { |
||
184 | ast->deint_id = avio_rl32(pb); |
||
185 | avio_read(pb, buf, 4); |
||
186 | buf[4] = 0; |
||
187 | } else { |
||
188 | get_str8(pb, buf, sizeof(buf)); /* desc */ |
||
189 | ast->deint_id = AV_RL32(buf); |
||
190 | get_str8(pb, buf, sizeof(buf)); /* desc */ |
||
191 | } |
||
192 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
||
193 | st->codec->codec_tag = AV_RL32(buf); |
||
194 | st->codec->codec_id = ff_codec_get_id(ff_rm_codec_tags, |
||
195 | st->codec->codec_tag); |
||
196 | |||
197 | switch (st->codec->codec_id) { |
||
198 | case AV_CODEC_ID_AC3: |
||
199 | st->need_parsing = AVSTREAM_PARSE_FULL; |
||
200 | break; |
||
201 | case AV_CODEC_ID_RA_288: |
||
202 | st->codec->extradata_size= 0; |
||
203 | ast->audio_framesize = st->codec->block_align; |
||
204 | st->codec->block_align = coded_framesize; |
||
205 | break; |
||
206 | case AV_CODEC_ID_COOK: |
||
207 | st->need_parsing = AVSTREAM_PARSE_HEADERS; |
||
208 | case AV_CODEC_ID_ATRAC3: |
||
209 | case AV_CODEC_ID_SIPR: |
||
210 | if (read_all) { |
||
211 | codecdata_length = 0; |
||
212 | } else { |
||
213 | avio_rb16(pb); avio_r8(pb); |
||
214 | if (version == 5) |
||
215 | avio_r8(pb); |
||
216 | codecdata_length = avio_rb32(pb); |
||
217 | if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ |
||
218 | av_log(s, AV_LOG_ERROR, "codecdata_length too large\n"); |
||
219 | return -1; |
||
220 | } |
||
221 | } |
||
222 | |||
223 | ast->audio_framesize = st->codec->block_align; |
||
224 | if (st->codec->codec_id == AV_CODEC_ID_SIPR) { |
||
225 | if (flavor > 3) { |
||
226 | av_log(s, AV_LOG_ERROR, "bad SIPR file flavor %d\n", |
||
227 | flavor); |
||
228 | return -1; |
||
229 | } |
||
230 | st->codec->block_align = ff_sipr_subpk_size[flavor]; |
||
231 | } else { |
||
232 | if(sub_packet_size <= 0){ |
||
233 | av_log(s, AV_LOG_ERROR, "sub_packet_size is invalid\n"); |
||
234 | return -1; |
||
235 | } |
||
236 | st->codec->block_align = ast->sub_packet_size; |
||
237 | } |
||
238 | if ((ret = rm_read_extradata(pb, st->codec, codecdata_length)) < 0) |
||
239 | return ret; |
||
240 | |||
241 | break; |
||
242 | case AV_CODEC_ID_AAC: |
||
243 | avio_rb16(pb); avio_r8(pb); |
||
244 | if (version == 5) |
||
245 | avio_r8(pb); |
||
246 | codecdata_length = avio_rb32(pb); |
||
247 | if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ |
||
248 | av_log(s, AV_LOG_ERROR, "codecdata_length too large\n"); |
||
249 | return -1; |
||
250 | } |
||
251 | if (codecdata_length >= 1) { |
||
252 | avio_r8(pb); |
||
253 | if ((ret = rm_read_extradata(pb, st->codec, codecdata_length - 1)) < 0) |
||
254 | return ret; |
||
255 | } |
||
256 | break; |
||
257 | default: |
||
258 | av_strlcpy(st->codec->codec_name, buf, sizeof(st->codec->codec_name)); |
||
259 | } |
||
260 | if (ast->deint_id == DEINT_ID_INT4 || |
||
261 | ast->deint_id == DEINT_ID_GENR || |
||
262 | ast->deint_id == DEINT_ID_SIPR) { |
||
263 | if (st->codec->block_align <= 0 || |
||
264 | ast->audio_framesize * sub_packet_h > (unsigned)INT_MAX || |
||
265 | ast->audio_framesize * sub_packet_h < st->codec->block_align) |
||
266 | return AVERROR_INVALIDDATA; |
||
267 | if (av_new_packet(&ast->pkt, ast->audio_framesize * sub_packet_h) < 0) |
||
268 | return AVERROR(ENOMEM); |
||
269 | } |
||
270 | switch (ast->deint_id) { |
||
271 | case DEINT_ID_INT4: |
||
272 | if (ast->coded_framesize > ast->audio_framesize || |
||
273 | sub_packet_h <= 1 || |
||
274 | ast->coded_framesize * sub_packet_h > (2 + (sub_packet_h & 1)) * ast->audio_framesize) |
||
275 | return AVERROR_INVALIDDATA; |
||
276 | break; |
||
277 | case DEINT_ID_GENR: |
||
278 | if (ast->sub_packet_size <= 0 || |
||
279 | ast->sub_packet_size > ast->audio_framesize) |
||
280 | return AVERROR_INVALIDDATA; |
||
281 | break; |
||
282 | case DEINT_ID_SIPR: |
||
283 | case DEINT_ID_INT0: |
||
284 | case DEINT_ID_VBRS: |
||
285 | case DEINT_ID_VBRF: |
||
286 | break; |
||
287 | default: |
||
288 | av_log(s, AV_LOG_ERROR, "Unknown interleaver %X\n", ast->deint_id); |
||
289 | return AVERROR_INVALIDDATA; |
||
290 | } |
||
291 | |||
292 | if (read_all) { |
||
293 | avio_r8(pb); |
||
294 | avio_r8(pb); |
||
295 | avio_r8(pb); |
||
296 | rm_read_metadata(s, pb, 0); |
||
297 | } |
||
298 | } |
||
299 | return 0; |
||
300 | } |
||
301 | |||
302 | int |
||
303 | ff_rm_read_mdpr_codecdata (AVFormatContext *s, AVIOContext *pb, |
||
304 | AVStream *st, RMStream *rst, int codec_data_size, const uint8_t *mime) |
||
305 | { |
||
306 | unsigned int v; |
||
307 | int size; |
||
308 | int64_t codec_pos; |
||
309 | int ret; |
||
310 | |||
311 | avpriv_set_pts_info(st, 64, 1, 1000); |
||
312 | codec_pos = avio_tell(pb); |
||
313 | v = avio_rb32(pb); |
||
314 | if (v == MKTAG(0xfd, 'a', 'r', '.')) { |
||
315 | /* ra type header */ |
||
316 | if (rm_read_audio_stream_info(s, pb, st, rst, 0)) |
||
317 | return -1; |
||
318 | } else if (v == MKBETAG('L', 'S', 'D', ':')) { |
||
319 | avio_seek(pb, -4, SEEK_CUR); |
||
320 | if ((ret = rm_read_extradata(pb, st->codec, codec_data_size)) < 0) |
||
321 | return ret; |
||
322 | |||
323 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
||
324 | st->codec->codec_tag = AV_RL32(st->codec->extradata); |
||
325 | st->codec->codec_id = ff_codec_get_id(ff_rm_codec_tags, |
||
326 | st->codec->codec_tag); |
||
327 | } else if(mime && !strcmp(mime, "logical-fileinfo")){ |
||
328 | int stream_count, rule_count, property_count, i; |
||
329 | ff_free_stream(s, st); |
||
330 | if (avio_rb16(pb) != 0) { |
||
331 | av_log(s, AV_LOG_WARNING, "Unsupported version\n"); |
||
332 | goto skip; |
||
333 | } |
||
334 | stream_count = avio_rb16(pb); |
||
335 | avio_skip(pb, 6*stream_count); |
||
336 | rule_count = avio_rb16(pb); |
||
337 | avio_skip(pb, 2*rule_count); |
||
338 | property_count = avio_rb16(pb); |
||
339 | for(i=0; i |
||
340 | uint8_t name[128], val[128]; |
||
341 | avio_rb32(pb); |
||
342 | if (avio_rb16(pb) != 0) { |
||
343 | av_log(s, AV_LOG_WARNING, "Unsupported Name value property version\n"); |
||
344 | goto skip; //FIXME skip just this one |
||
345 | } |
||
346 | get_str8(pb, name, sizeof(name)); |
||
347 | switch(avio_rb32(pb)) { |
||
348 | case 2: get_strl(pb, val, sizeof(val), avio_rb16(pb)); |
||
349 | av_dict_set(&s->metadata, name, val, 0); |
||
350 | break; |
||
351 | default: avio_skip(pb, avio_rb16(pb)); |
||
352 | } |
||
353 | } |
||
354 | } else { |
||
355 | int fps; |
||
356 | if (avio_rl32(pb) != MKTAG('V', 'I', 'D', 'O')) { |
||
357 | fail1: |
||
358 | av_log(s, AV_LOG_WARNING, "Unsupported stream type %08x\n", v); |
||
359 | goto skip; |
||
360 | } |
||
361 | st->codec->codec_tag = avio_rl32(pb); |
||
362 | st->codec->codec_id = ff_codec_get_id(ff_rm_codec_tags, |
||
363 | st->codec->codec_tag); |
||
364 | av_dlog(s, "%X %X\n", st->codec->codec_tag, MKTAG('R', 'V', '2', '0')); |
||
365 | if (st->codec->codec_id == AV_CODEC_ID_NONE) |
||
366 | goto fail1; |
||
367 | st->codec->width = avio_rb16(pb); |
||
368 | st->codec->height = avio_rb16(pb); |
||
369 | avio_skip(pb, 2); // looks like bits per sample |
||
370 | avio_skip(pb, 4); // always zero? |
||
371 | st->codec->codec_type = AVMEDIA_TYPE_VIDEO; |
||
372 | st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS; |
||
373 | fps = avio_rb32(pb); |
||
374 | |||
375 | if ((ret = rm_read_extradata(pb, st->codec, codec_data_size - (avio_tell(pb) - codec_pos))) < 0) |
||
376 | return ret; |
||
377 | |||
378 | if (fps > 0) { |
||
379 | av_reduce(&st->avg_frame_rate.den, &st->avg_frame_rate.num, |
||
380 | 0x10000, fps, (1 << 30) - 1); |
||
381 | #if FF_API_R_FRAME_RATE |
||
382 | st->r_frame_rate = st->avg_frame_rate; |
||
383 | #endif |
||
384 | } else if (s->error_recognition & AV_EF_EXPLODE) { |
||
385 | av_log(s, AV_LOG_ERROR, "Invalid framerate\n"); |
||
386 | return AVERROR_INVALIDDATA; |
||
387 | } |
||
388 | } |
||
389 | |||
390 | skip: |
||
391 | /* skip codec info */ |
||
392 | size = avio_tell(pb) - codec_pos; |
||
393 | avio_skip(pb, codec_data_size - size); |
||
394 | |||
395 | return 0; |
||
396 | } |
||
397 | |||
398 | /** this function assumes that the demuxer has already seeked to the start |
||
399 | * of the INDX chunk, and will bail out if not. */ |
||
400 | static int rm_read_index(AVFormatContext *s) |
||
401 | { |
||
402 | AVIOContext *pb = s->pb; |
||
403 | unsigned int size, n_pkts, str_id, next_off, n, pos, pts; |
||
404 | AVStream *st; |
||
405 | |||
406 | do { |
||
407 | if (avio_rl32(pb) != MKTAG('I','N','D','X')) |
||
408 | return -1; |
||
409 | size = avio_rb32(pb); |
||
410 | if (size < 20) |
||
411 | return -1; |
||
412 | avio_skip(pb, 2); |
||
413 | n_pkts = avio_rb32(pb); |
||
414 | str_id = avio_rb16(pb); |
||
415 | next_off = avio_rb32(pb); |
||
416 | for (n = 0; n < s->nb_streams; n++) |
||
417 | if (s->streams[n]->id == str_id) { |
||
418 | st = s->streams[n]; |
||
419 | break; |
||
420 | } |
||
421 | if (n == s->nb_streams) { |
||
422 | av_log(s, AV_LOG_ERROR, |
||
423 | "Invalid stream index %d for index at pos %"PRId64"\n", |
||
424 | str_id, avio_tell(pb)); |
||
425 | goto skip; |
||
426 | } else if ((avio_size(pb) - avio_tell(pb)) / 14 < n_pkts) { |
||
427 | av_log(s, AV_LOG_ERROR, |
||
428 | "Nr. of packets in packet index for stream index %d " |
||
429 | "exceeds filesize (%"PRId64" at %"PRId64" = %"PRId64")\n", |
||
430 | str_id, avio_size(pb), avio_tell(pb), |
||
431 | (avio_size(pb) - avio_tell(pb)) / 14); |
||
432 | goto skip; |
||
433 | } |
||
434 | |||
435 | for (n = 0; n < n_pkts; n++) { |
||
436 | avio_skip(pb, 2); |
||
437 | pts = avio_rb32(pb); |
||
438 | pos = avio_rb32(pb); |
||
439 | avio_skip(pb, 4); /* packet no. */ |
||
440 | |||
441 | av_add_index_entry(st, pos, pts, 0, 0, AVINDEX_KEYFRAME); |
||
442 | } |
||
443 | |||
444 | skip: |
||
445 | if (next_off && avio_tell(pb) < next_off && |
||
446 | avio_seek(pb, next_off, SEEK_SET) < 0) { |
||
447 | av_log(s, AV_LOG_ERROR, |
||
448 | "Non-linear index detected, not supported\n"); |
||
449 | return -1; |
||
450 | } |
||
451 | } while (next_off); |
||
452 | |||
453 | return 0; |
||
454 | } |
||
455 | |||
456 | static int rm_read_header_old(AVFormatContext *s) |
||
457 | { |
||
458 | RMDemuxContext *rm = s->priv_data; |
||
459 | AVStream *st; |
||
460 | |||
461 | rm->old_format = 1; |
||
462 | st = avformat_new_stream(s, NULL); |
||
463 | if (!st) |
||
464 | return -1; |
||
465 | st->priv_data = ff_rm_alloc_rmstream(); |
||
466 | return rm_read_audio_stream_info(s, s->pb, st, st->priv_data, 1); |
||
467 | } |
||
468 | |||
469 | static int rm_read_header(AVFormatContext *s) |
||
470 | { |
||
471 | RMDemuxContext *rm = s->priv_data; |
||
472 | AVStream *st; |
||
473 | AVIOContext *pb = s->pb; |
||
474 | unsigned int tag; |
||
475 | int tag_size; |
||
476 | unsigned int start_time, duration; |
||
477 | unsigned int data_off = 0, indx_off = 0; |
||
478 | char buf[128], mime[128]; |
||
479 | int flags = 0; |
||
480 | |||
481 | tag = avio_rl32(pb); |
||
482 | if (tag == MKTAG('.', 'r', 'a', 0xfd)) { |
||
483 | /* very old .ra format */ |
||
484 | return rm_read_header_old(s); |
||
485 | } else if (tag != MKTAG('.', 'R', 'M', 'F')) { |
||
486 | return AVERROR(EIO); |
||
487 | } |
||
488 | |||
489 | tag_size = avio_rb32(pb); |
||
490 | avio_skip(pb, tag_size - 8); |
||
491 | |||
492 | for(;;) { |
||
493 | if (url_feof(pb)) |
||
494 | return -1; |
||
495 | tag = avio_rl32(pb); |
||
496 | tag_size = avio_rb32(pb); |
||
497 | avio_rb16(pb); |
||
498 | av_dlog(s, "tag=%c%c%c%c (%08x) size=%d\n", |
||
499 | (tag ) & 0xff, |
||
500 | (tag >> 8) & 0xff, |
||
501 | (tag >> 16) & 0xff, |
||
502 | (tag >> 24) & 0xff, |
||
503 | tag, |
||
504 | tag_size); |
||
505 | if (tag_size < 10 && tag != MKTAG('D', 'A', 'T', 'A')) |
||
506 | return -1; |
||
507 | switch(tag) { |
||
508 | case MKTAG('P', 'R', 'O', 'P'): |
||
509 | /* file header */ |
||
510 | avio_rb32(pb); /* max bit rate */ |
||
511 | avio_rb32(pb); /* avg bit rate */ |
||
512 | avio_rb32(pb); /* max packet size */ |
||
513 | avio_rb32(pb); /* avg packet size */ |
||
514 | avio_rb32(pb); /* nb packets */ |
||
515 | duration = avio_rb32(pb); /* duration */ |
||
516 | s->duration = av_rescale(duration, AV_TIME_BASE, 1000); |
||
517 | avio_rb32(pb); /* preroll */ |
||
518 | indx_off = avio_rb32(pb); /* index offset */ |
||
519 | data_off = avio_rb32(pb); /* data offset */ |
||
520 | avio_rb16(pb); /* nb streams */ |
||
521 | flags = avio_rb16(pb); /* flags */ |
||
522 | break; |
||
523 | case MKTAG('C', 'O', 'N', 'T'): |
||
524 | rm_read_metadata(s, pb, 1); |
||
525 | break; |
||
526 | case MKTAG('M', 'D', 'P', 'R'): |
||
527 | st = avformat_new_stream(s, NULL); |
||
528 | if (!st) |
||
529 | return AVERROR(ENOMEM); |
||
530 | st->id = avio_rb16(pb); |
||
531 | avio_rb32(pb); /* max bit rate */ |
||
532 | st->codec->bit_rate = avio_rb32(pb); /* bit rate */ |
||
533 | avio_rb32(pb); /* max packet size */ |
||
534 | avio_rb32(pb); /* avg packet size */ |
||
535 | start_time = avio_rb32(pb); /* start time */ |
||
536 | avio_rb32(pb); /* preroll */ |
||
537 | duration = avio_rb32(pb); /* duration */ |
||
538 | st->start_time = start_time; |
||
539 | st->duration = duration; |
||
540 | if(duration>0) |
||
541 | s->duration = AV_NOPTS_VALUE; |
||
542 | get_str8(pb, buf, sizeof(buf)); /* desc */ |
||
543 | get_str8(pb, mime, sizeof(mime)); /* mimetype */ |
||
544 | st->codec->codec_type = AVMEDIA_TYPE_DATA; |
||
545 | st->priv_data = ff_rm_alloc_rmstream(); |
||
546 | if (ff_rm_read_mdpr_codecdata(s, s->pb, st, st->priv_data, |
||
547 | avio_rb32(pb), mime) < 0) |
||
548 | return -1; |
||
549 | break; |
||
550 | case MKTAG('D', 'A', 'T', 'A'): |
||
551 | goto header_end; |
||
552 | default: |
||
553 | /* unknown tag: skip it */ |
||
554 | avio_skip(pb, tag_size - 10); |
||
555 | break; |
||
556 | } |
||
557 | } |
||
558 | header_end: |
||
559 | rm->nb_packets = avio_rb32(pb); /* number of packets */ |
||
560 | if (!rm->nb_packets && (flags & 4)) |
||
561 | rm->nb_packets = 3600 * 25; |
||
562 | avio_rb32(pb); /* next data header */ |
||
563 | |||
564 | if (!data_off) |
||
565 | data_off = avio_tell(pb) - 18; |
||
566 | if (indx_off && pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) && |
||
567 | avio_seek(pb, indx_off, SEEK_SET) >= 0) { |
||
568 | rm_read_index(s); |
||
569 | avio_seek(pb, data_off + 18, SEEK_SET); |
||
570 | } |
||
571 | |||
572 | return 0; |
||
573 | } |
||
574 | |||
575 | static int get_num(AVIOContext *pb, int *len) |
||
576 | { |
||
577 | int n, n1; |
||
578 | |||
579 | n = avio_rb16(pb); |
||
580 | (*len)-=2; |
||
581 | n &= 0x7FFF; |
||
582 | if (n >= 0x4000) { |
||
583 | return n - 0x4000; |
||
584 | } else { |
||
585 | n1 = avio_rb16(pb); |
||
586 | (*len)-=2; |
||
587 | return (n << 16) | n1; |
||
588 | } |
||
589 | } |
||
590 | |||
591 | /* multiple of 20 bytes for ra144 (ugly) */ |
||
592 | #define RAW_PACKET_SIZE 1000 |
||
593 | |||
594 | static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_index, int64_t *pos){ |
||
595 | RMDemuxContext *rm = s->priv_data; |
||
596 | AVIOContext *pb = s->pb; |
||
597 | AVStream *st; |
||
598 | uint32_t state=0xFFFFFFFF; |
||
599 | |||
600 | while(!url_feof(pb)){ |
||
601 | int len, num, i; |
||
602 | *pos= avio_tell(pb) - 3; |
||
603 | if(rm->remaining_len > 0){ |
||
604 | num= rm->current_stream; |
||
605 | len= rm->remaining_len; |
||
606 | *timestamp = AV_NOPTS_VALUE; |
||
607 | *flags= 0; |
||
608 | }else{ |
||
609 | state= (state<<8) + avio_r8(pb); |
||
610 | |||
611 | if(state == MKBETAG('I', 'N', 'D', 'X')){ |
||
612 | int n_pkts, expected_len; |
||
613 | len = avio_rb32(pb); |
||
614 | avio_skip(pb, 2); |
||
615 | n_pkts = avio_rb32(pb); |
||
616 | expected_len = 20 + n_pkts * 14; |
||
617 | if (len == 20) |
||
618 | /* some files don't add index entries to chunk size... */ |
||
619 | len = expected_len; |
||
620 | else if (len != expected_len) |
||
621 | av_log(s, AV_LOG_WARNING, |
||
622 | "Index size %d (%d pkts) is wrong, should be %d.\n", |
||
623 | len, n_pkts, expected_len); |
||
624 | len -= 14; // we already read part of the index header |
||
625 | if(len<0) |
||
626 | continue; |
||
627 | goto skip; |
||
628 | } else if (state == MKBETAG('D','A','T','A')) { |
||
629 | av_log(s, AV_LOG_WARNING, |
||
630 | "DATA tag in middle of chunk, file may be broken.\n"); |
||
631 | } |
||
632 | |||
633 | if(state > (unsigned)0xFFFF || state <= 12) |
||
634 | continue; |
||
635 | len=state - 12; |
||
636 | state= 0xFFFFFFFF; |
||
637 | |||
638 | num = avio_rb16(pb); |
||
639 | *timestamp = avio_rb32(pb); |
||
640 | avio_r8(pb); /* reserved */ |
||
641 | *flags = avio_r8(pb); /* flags */ |
||
642 | } |
||
643 | for(i=0;i |
||
644 | st = s->streams[i]; |
||
645 | if (num == st->id) |
||
646 | break; |
||
647 | } |
||
648 | if (i == s->nb_streams) { |
||
649 | skip: |
||
650 | /* skip packet if unknown number */ |
||
651 | avio_skip(pb, len); |
||
652 | rm->remaining_len = 0; |
||
653 | continue; |
||
654 | } |
||
655 | *stream_index= i; |
||
656 | |||
657 | return len; |
||
658 | } |
||
659 | return -1; |
||
660 | } |
||
661 | |||
662 | static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb, |
||
663 | RMDemuxContext *rm, RMStream *vst, |
||
664 | AVPacket *pkt, int len, int *pseq, |
||
665 | int64_t *timestamp) |
||
666 | { |
||
667 | int hdr; |
||
668 | int seq = 0, pic_num = 0, len2 = 0, pos = 0; //init to silcense compiler warning |
||
669 | int type; |
||
670 | int ret; |
||
671 | |||
672 | hdr = avio_r8(pb); len--; |
||
673 | type = hdr >> 6; |
||
674 | |||
675 | if(type != 3){ // not frame as a part of packet |
||
676 | seq = avio_r8(pb); len--; |
||
677 | } |
||
678 | if(type != 1){ // not whole frame |
||
679 | len2 = get_num(pb, &len); |
||
680 | pos = get_num(pb, &len); |
||
681 | pic_num = avio_r8(pb); len--; |
||
682 | } |
||
683 | if(len<0) { |
||
684 | av_log(s, AV_LOG_ERROR, "Insufficient data\n"); |
||
685 | return -1; |
||
686 | } |
||
687 | rm->remaining_len = len; |
||
688 | if(type&1){ // frame, not slice |
||
689 | if(type == 3){ // frame as a part of packet |
||
690 | len= len2; |
||
691 | *timestamp = pos; |
||
692 | } |
||
693 | if(rm->remaining_len < len) { |
||
694 | av_log(s, AV_LOG_ERROR, "Insufficient remaining len\n"); |
||
695 | return -1; |
||
696 | } |
||
697 | rm->remaining_len -= len; |
||
698 | if(av_new_packet(pkt, len + 9) < 0) |
||
699 | return AVERROR(EIO); |
||
700 | pkt->data[0] = 0; |
||
701 | AV_WL32(pkt->data + 1, 1); |
||
702 | AV_WL32(pkt->data + 5, 0); |
||
703 | if ((ret = avio_read(pb, pkt->data + 9, len)) != len) { |
||
704 | av_free_packet(pkt); |
||
705 | av_log(s, AV_LOG_ERROR, "Failed to read %d bytes\n", len); |
||
706 | return ret < 0 ? ret : AVERROR(EIO); |
||
707 | } |
||
708 | return 0; |
||
709 | } |
||
710 | //now we have to deal with single slice |
||
711 | |||
712 | *pseq = seq; |
||
713 | if((seq & 0x7F) == 1 || vst->curpic_num != pic_num){ |
||
714 | if (len2 > ffio_limit(pb, len2)) { |
||
715 | av_log(s, AV_LOG_ERROR, "Impossibly sized packet\n"); |
||
716 | return AVERROR_INVALIDDATA; |
||
717 | } |
||
718 | vst->slices = ((hdr & 0x3F) << 1) + 1; |
||
719 | vst->videobufsize = len2 + 8*vst->slices + 1; |
||
720 | av_free_packet(&vst->pkt); //FIXME this should be output. |
||
721 | if(av_new_packet(&vst->pkt, vst->videobufsize) < 0) |
||
722 | return AVERROR(ENOMEM); |
||
723 | memset(vst->pkt.data, 0, vst->pkt.size); |
||
724 | vst->videobufpos = 8*vst->slices + 1; |
||
725 | vst->cur_slice = 0; |
||
726 | vst->curpic_num = pic_num; |
||
727 | vst->pktpos = avio_tell(pb); |
||
728 | } |
||
729 | if(type == 2) |
||
730 | len = FFMIN(len, pos); |
||
731 | |||
732 | if(++vst->cur_slice > vst->slices) { |
||
733 | av_log(s, AV_LOG_ERROR, "cur slice %d, too large\n", vst->cur_slice); |
||
734 | return 1; |
||
735 | } |
||
736 | if(!vst->pkt.data) |
||
737 | return AVERROR(ENOMEM); |
||
738 | AV_WL32(vst->pkt.data - 7 + 8*vst->cur_slice, 1); |
||
739 | AV_WL32(vst->pkt.data - 3 + 8*vst->cur_slice, vst->videobufpos - 8*vst->slices - 1); |
||
740 | if(vst->videobufpos + len > vst->videobufsize) { |
||
741 | av_log(s, AV_LOG_ERROR, "outside videobufsize\n"); |
||
742 | return 1; |
||
743 | } |
||
744 | if (avio_read(pb, vst->pkt.data + vst->videobufpos, len) != len) |
||
745 | return AVERROR(EIO); |
||
746 | vst->videobufpos += len; |
||
747 | rm->remaining_len-= len; |
||
748 | |||
749 | if (type == 2 || vst->videobufpos == vst->videobufsize) { |
||
750 | vst->pkt.data[0] = vst->cur_slice-1; |
||
751 | *pkt= vst->pkt; |
||
752 | vst->pkt.data= NULL; |
||
753 | vst->pkt.size= 0; |
||
754 | vst->pkt.buf = NULL; |
||
755 | #if FF_API_DESTRUCT_PACKET |
||
756 | FF_DISABLE_DEPRECATION_WARNINGS |
||
757 | vst->pkt.destruct = NULL; |
||
758 | FF_ENABLE_DEPRECATION_WARNINGS |
||
759 | #endif |
||
760 | if(vst->slices != vst->cur_slice) //FIXME find out how to set slices correct from the begin |
||
761 | memmove(pkt->data + 1 + 8*vst->cur_slice, pkt->data + 1 + 8*vst->slices, |
||
762 | vst->videobufpos - 1 - 8*vst->slices); |
||
763 | pkt->size = vst->videobufpos + 8*(vst->cur_slice - vst->slices); |
||
764 | pkt->pts = AV_NOPTS_VALUE; |
||
765 | pkt->pos = vst->pktpos; |
||
766 | vst->slices = 0; |
||
767 | return 0; |
||
768 | } |
||
769 | |||
770 | return 1; |
||
771 | } |
||
772 | |||
773 | static inline void |
||
774 | rm_ac3_swap_bytes (AVStream *st, AVPacket *pkt) |
||
775 | { |
||
776 | uint8_t *ptr; |
||
777 | int j; |
||
778 | |||
779 | if (st->codec->codec_id == AV_CODEC_ID_AC3) { |
||
780 | ptr = pkt->data; |
||
781 | for (j=0;j |
||
782 | FFSWAP(int, ptr[0], ptr[1]); |
||
783 | ptr += 2; |
||
784 | } |
||
785 | } |
||
786 | } |
||
787 | |||
788 | int |
||
789 | ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb, |
||
790 | AVStream *st, RMStream *ast, int len, AVPacket *pkt, |
||
791 | int *seq, int flags, int64_t timestamp) |
||
792 | { |
||
793 | RMDemuxContext *rm = s->priv_data; |
||
794 | int ret; |
||
795 | |||
796 | if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { |
||
797 | rm->current_stream= st->id; |
||
798 | ret = rm_assemble_video_frame(s, pb, rm, ast, pkt, len, seq, ×tamp); |
||
799 | if(ret) |
||
800 | return ret < 0 ? ret : -1; //got partial frame or error |
||
801 | } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { |
||
802 | if ((ast->deint_id == DEINT_ID_GENR) || |
||
803 | (ast->deint_id == DEINT_ID_INT4) || |
||
804 | (ast->deint_id == DEINT_ID_SIPR)) { |
||
805 | int x; |
||
806 | int sps = ast->sub_packet_size; |
||
807 | int cfs = ast->coded_framesize; |
||
808 | int h = ast->sub_packet_h; |
||
809 | int y = ast->sub_packet_cnt; |
||
810 | int w = ast->audio_framesize; |
||
811 | |||
812 | if (flags & 2) |
||
813 | y = ast->sub_packet_cnt = 0; |
||
814 | if (!y) |
||
815 | ast->audiotimestamp = timestamp; |
||
816 | |||
817 | switch (ast->deint_id) { |
||
818 | case DEINT_ID_INT4: |
||
819 | for (x = 0; x < h/2; x++) |
||
820 | avio_read(pb, ast->pkt.data+x*2*w+y*cfs, cfs); |
||
821 | break; |
||
822 | case DEINT_ID_GENR: |
||
823 | for (x = 0; x < w/sps; x++) |
||
824 | avio_read(pb, ast->pkt.data+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), sps); |
||
825 | break; |
||
826 | case DEINT_ID_SIPR: |
||
827 | avio_read(pb, ast->pkt.data + y * w, w); |
||
828 | break; |
||
829 | } |
||
830 | |||
831 | if (++(ast->sub_packet_cnt) < h) |
||
832 | return -1; |
||
833 | if (ast->deint_id == DEINT_ID_SIPR) |
||
834 | ff_rm_reorder_sipr_data(ast->pkt.data, h, w); |
||
835 | |||
836 | ast->sub_packet_cnt = 0; |
||
837 | rm->audio_stream_num = st->index; |
||
838 | rm->audio_pkt_cnt = h * w / st->codec->block_align; |
||
839 | } else if ((ast->deint_id == DEINT_ID_VBRF) || |
||
840 | (ast->deint_id == DEINT_ID_VBRS)) { |
||
841 | int x; |
||
842 | rm->audio_stream_num = st->index; |
||
843 | ast->sub_packet_cnt = (avio_rb16(pb) & 0xf0) >> 4; |
||
844 | if (ast->sub_packet_cnt) { |
||
845 | for (x = 0; x < ast->sub_packet_cnt; x++) |
||
846 | ast->sub_packet_lengths[x] = avio_rb16(pb); |
||
847 | rm->audio_pkt_cnt = ast->sub_packet_cnt; |
||
848 | ast->audiotimestamp = timestamp; |
||
849 | } else |
||
850 | return -1; |
||
851 | } else { |
||
852 | av_get_packet(pb, pkt, len); |
||
853 | rm_ac3_swap_bytes(st, pkt); |
||
854 | } |
||
855 | } else |
||
856 | av_get_packet(pb, pkt, len); |
||
857 | |||
858 | pkt->stream_index = st->index; |
||
859 | |||
860 | #if 0 |
||
861 | if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { |
||
862 | if(st->codec->codec_id == AV_CODEC_ID_RV20){ |
||
863 | int seq= 128*(pkt->data[2]&0x7F) + (pkt->data[3]>>1); |
||
864 | av_log(s, AV_LOG_DEBUG, "%d %"PRId64" %d\n", *timestamp, *timestamp*512LL/25, seq); |
||
865 | |||
866 | seq |= (timestamp&~0x3FFF); |
||
867 | if(seq - timestamp > 0x2000) seq -= 0x4000; |
||
868 | if(seq - timestamp < -0x2000) seq += 0x4000; |
||
869 | } |
||
870 | } |
||
871 | #endif |
||
872 | |||
873 | pkt->pts = timestamp; |
||
874 | if (flags & 2) |
||
875 | pkt->flags |= AV_PKT_FLAG_KEY; |
||
876 | |||
877 | return st->codec->codec_type == AVMEDIA_TYPE_AUDIO ? rm->audio_pkt_cnt : 0; |
||
878 | } |
||
879 | |||
880 | int |
||
881 | ff_rm_retrieve_cache (AVFormatContext *s, AVIOContext *pb, |
||
882 | AVStream *st, RMStream *ast, AVPacket *pkt) |
||
883 | { |
||
884 | RMDemuxContext *rm = s->priv_data; |
||
885 | |||
886 | av_assert0 (rm->audio_pkt_cnt > 0); |
||
887 | |||
888 | if (ast->deint_id == DEINT_ID_VBRF || |
||
889 | ast->deint_id == DEINT_ID_VBRS) |
||
890 | av_get_packet(pb, pkt, ast->sub_packet_lengths[ast->sub_packet_cnt - rm->audio_pkt_cnt]); |
||
891 | else { |
||
892 | if(av_new_packet(pkt, st->codec->block_align) < 0) |
||
893 | return AVERROR(ENOMEM); |
||
894 | memcpy(pkt->data, ast->pkt.data + st->codec->block_align * //FIXME avoid this |
||
895 | (ast->sub_packet_h * ast->audio_framesize / st->codec->block_align - rm->audio_pkt_cnt), |
||
896 | st->codec->block_align); |
||
897 | } |
||
898 | rm->audio_pkt_cnt--; |
||
899 | if ((pkt->pts = ast->audiotimestamp) != AV_NOPTS_VALUE) { |
||
900 | ast->audiotimestamp = AV_NOPTS_VALUE; |
||
901 | pkt->flags = AV_PKT_FLAG_KEY; |
||
902 | } else |
||
903 | pkt->flags = 0; |
||
904 | pkt->stream_index = st->index; |
||
905 | |||
906 | return rm->audio_pkt_cnt; |
||
907 | } |
||
908 | |||
909 | static int rm_read_packet(AVFormatContext *s, AVPacket *pkt) |
||
910 | { |
||
911 | RMDemuxContext *rm = s->priv_data; |
||
912 | AVStream *st = NULL; // init to silence compiler warning |
||
913 | int i, len, res, seq = 1; |
||
914 | int64_t timestamp, pos; |
||
915 | int flags; |
||
916 | |||
917 | for (;;) { |
||
918 | if (rm->audio_pkt_cnt) { |
||
919 | // If there are queued audio packet return them first |
||
920 | st = s->streams[rm->audio_stream_num]; |
||
921 | res = ff_rm_retrieve_cache(s, s->pb, st, st->priv_data, pkt); |
||
922 | if(res < 0) |
||
923 | return res; |
||
924 | flags = 0; |
||
925 | } else { |
||
926 | if (rm->old_format) { |
||
927 | RMStream *ast; |
||
928 | |||
929 | st = s->streams[0]; |
||
930 | ast = st->priv_data; |
||
931 | timestamp = AV_NOPTS_VALUE; |
||
932 | len = !ast->audio_framesize ? RAW_PACKET_SIZE : |
||
933 | ast->coded_framesize * ast->sub_packet_h / 2; |
||
934 | flags = (seq++ == 1) ? 2 : 0; |
||
935 | pos = avio_tell(s->pb); |
||
936 | } else { |
||
937 | len=sync(s, ×tamp, &flags, &i, &pos); |
||
938 | if (len > 0) |
||
939 | st = s->streams[i]; |
||
940 | } |
||
941 | |||
942 | if(len<0 || url_feof(s->pb)) |
||
943 | return AVERROR(EIO); |
||
944 | |||
945 | res = ff_rm_parse_packet (s, s->pb, st, st->priv_data, len, pkt, |
||
946 | &seq, flags, timestamp); |
||
947 | if (res < -1) |
||
948 | return res; |
||
949 | if((flags&2) && (seq&0x7F) == 1) |
||
950 | av_add_index_entry(st, pos, timestamp, 0, 0, AVINDEX_KEYFRAME); |
||
951 | if (res) |
||
952 | continue; |
||
953 | } |
||
954 | |||
955 | if( (st->discard >= AVDISCARD_NONKEY && !(flags&2)) |
||
956 | || st->discard >= AVDISCARD_ALL){ |
||
957 | av_free_packet(pkt); |
||
958 | } else |
||
959 | break; |
||
960 | } |
||
961 | |||
962 | return 0; |
||
963 | } |
||
964 | |||
965 | static int rm_read_close(AVFormatContext *s) |
||
966 | { |
||
967 | int i; |
||
968 | |||
969 | for (i=0;i |
||
970 | ff_rm_free_rmstream(s->streams[i]->priv_data); |
||
971 | |||
972 | return 0; |
||
973 | } |
||
974 | |||
975 | static int rm_probe(AVProbeData *p) |
||
976 | { |
||
977 | /* check file header */ |
||
978 | if ((p->buf[0] == '.' && p->buf[1] == 'R' && |
||
979 | p->buf[2] == 'M' && p->buf[3] == 'F' && |
||
980 | p->buf[4] == 0 && p->buf[5] == 0) || |
||
981 | (p->buf[0] == '.' && p->buf[1] == 'r' && |
||
982 | p->buf[2] == 'a' && p->buf[3] == 0xfd)) |
||
983 | return AVPROBE_SCORE_MAX; |
||
984 | else |
||
985 | return 0; |
||
986 | } |
||
987 | |||
988 | static int64_t rm_read_dts(AVFormatContext *s, int stream_index, |
||
989 | int64_t *ppos, int64_t pos_limit) |
||
990 | { |
||
991 | RMDemuxContext *rm = s->priv_data; |
||
992 | int64_t pos, dts; |
||
993 | int stream_index2, flags, len, h; |
||
994 | |||
995 | pos = *ppos; |
||
996 | |||
997 | if(rm->old_format) |
||
998 | return AV_NOPTS_VALUE; |
||
999 | |||
1000 | if (avio_seek(s->pb, pos, SEEK_SET) < 0) |
||
1001 | return AV_NOPTS_VALUE; |
||
1002 | |||
1003 | rm->remaining_len=0; |
||
1004 | for(;;){ |
||
1005 | int seq=1; |
||
1006 | AVStream *st; |
||
1007 | |||
1008 | len=sync(s, &dts, &flags, &stream_index2, &pos); |
||
1009 | if(len<0) |
||
1010 | return AV_NOPTS_VALUE; |
||
1011 | |||
1012 | st = s->streams[stream_index2]; |
||
1013 | if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { |
||
1014 | h= avio_r8(s->pb); len--; |
||
1015 | if(!(h & 0x40)){ |
||
1016 | seq = avio_r8(s->pb); len--; |
||
1017 | } |
||
1018 | } |
||
1019 | |||
1020 | if((flags&2) && (seq&0x7F) == 1){ |
||
1021 | av_dlog(s, "%d %d-%d %"PRId64" %d\n", |
||
1022 | flags, stream_index2, stream_index, dts, seq); |
||
1023 | av_add_index_entry(st, pos, dts, 0, 0, AVINDEX_KEYFRAME); |
||
1024 | if(stream_index2 == stream_index) |
||
1025 | break; |
||
1026 | } |
||
1027 | |||
1028 | avio_skip(s->pb, len); |
||
1029 | } |
||
1030 | *ppos = pos; |
||
1031 | return dts; |
||
1032 | } |
||
1033 | |||
1034 | static int rm_read_seek(AVFormatContext *s, int stream_index, |
||
1035 | int64_t pts, int flags) |
||
1036 | { |
||
1037 | RMDemuxContext *rm = s->priv_data; |
||
1038 | |||
1039 | if (ff_seek_frame_binary(s, stream_index, pts, flags) < 0) |
||
1040 | return -1; |
||
1041 | rm->audio_pkt_cnt = 0; |
||
1042 | return 0; |
||
1043 | } |
||
1044 | |||
1045 | |||
1046 | AVInputFormat ff_rm_demuxer = { |
||
1047 | .name = "rm", |
||
1048 | .long_name = NULL_IF_CONFIG_SMALL("RealMedia"), |
||
1049 | .priv_data_size = sizeof(RMDemuxContext), |
||
1050 | .read_probe = rm_probe, |
||
1051 | .read_header = rm_read_header, |
||
1052 | .read_packet = rm_read_packet, |
||
1053 | .read_close = rm_read_close, |
||
1054 | .read_timestamp = rm_read_dts, |
||
1055 | .read_seek = rm_read_seek, |
||
1056 | }; |
||
1057 | |||
1058 | AVInputFormat ff_rdt_demuxer = { |
||
1059 | .name = "rdt", |
||
1060 | .long_name = NULL_IF_CONFIG_SMALL("RDT demuxer"), |
||
1061 | .priv_data_size = sizeof(RMDemuxContext), |
||
1062 | .read_close = rm_read_close, |
||
1063 | .flags = AVFMT_NOFILE, |
||
1064 | };>0) |