Commit | Line | Data |
---|---|---|
de6d9b64 | 1 | /* |
7b2a2ce5 | 2 | * "Real" compatible demuxer. |
19720f15 | 3 | * Copyright (c) 2000, 2001 Fabrice Bellard. |
de6d9b64 | 4 | * |
b78e7197 DB |
5 | * This file is part of FFmpeg. |
6 | * | |
7 | * FFmpeg is free software; you can redistribute it and/or | |
19720f15 FB |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either | |
b78e7197 | 10 | * version 2.1 of the License, or (at your option) any later version. |
de6d9b64 | 11 | * |
b78e7197 | 12 | * FFmpeg is distributed in the hope that it will be useful, |
de6d9b64 | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19720f15 FB |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. | |
de6d9b64 | 16 | * |
19720f15 | 17 | * You should have received a copy of the GNU Lesser General Public |
b78e7197 | 18 | * License along with FFmpeg; if not, write to the Free Software |
5509bffa | 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
de6d9b64 | 20 | */ |
245976da DB |
21 | |
22 | #include "libavutil/avstring.h" | |
de6d9b64 | 23 | #include "avformat.h" |
ba614729 | 24 | #include "rm.h" |
1edddc99 | 25 | |
ba614729 | 26 | struct RMStream { |
1edddc99 RB |
27 | uint8_t *videobuf; ///< place to store merged video frame |
28 | int videobufsize; ///< current assembled frame size | |
29 | int videobufpos; ///< position for the next slice in the video buffer | |
30 | int curpic_num; ///< picture number of current frame | |
31 | int cur_slice, slices; | |
32 | int64_t pktpos; ///< first slice position in file | |
33 | /// Audio descrambling matrix parameters | |
34 | uint8_t *audiobuf; ///< place to store reordered audio data | |
35 | int64_t audiotimestamp; ///< Audio packet timestamp | |
36 | int sub_packet_cnt; // Subpacket counter, used while reading | |
37 | int sub_packet_size, sub_packet_h, coded_framesize; ///< Descrambling parameters from container | |
ba614729 RB |
38 | int audio_framesize; /// Audio frame size from container |
39 | int sub_packet_lengths[16]; /// Length of each subpacket | |
40 | }; | |
41 | ||
42 | typedef struct { | |
43 | int nb_packets; | |
44 | int old_format; | |
45 | int current_stream; | |
46 | int remaining_len; | |
1edddc99 RB |
47 | int audio_stream_num; ///< Stream number for audio packets |
48 | int audio_pkt_cnt; ///< Output packet counter | |
1edddc99 | 49 | } RMDemuxContext; |
de6d9b64 | 50 | |
36cf20f5 | 51 | static inline void get_strl(ByteIOContext *pb, char *buf, int buf_size, int len) |
de6d9b64 | 52 | { |
36cf20f5 | 53 | int i; |
28263f5f | 54 | char *q, r; |
de6d9b64 | 55 | |
de6d9b64 FB |
56 | q = buf; |
57 | for(i=0;i<len;i++) { | |
28263f5f | 58 | r = get_byte(pb); |
de6d9b64 | 59 | if (i < buf_size - 1) |
28263f5f | 60 | *q++ = r; |
de6d9b64 | 61 | } |
28263f5f | 62 | if (buf_size > 0) *q = '\0'; |
de6d9b64 FB |
63 | } |
64 | ||
36cf20f5 | 65 | static void get_str16(ByteIOContext *pb, char *buf, int buf_size) |
de6d9b64 | 66 | { |
36cf20f5 RB |
67 | get_strl(pb, buf, buf_size, get_be16(pb)); |
68 | } | |
de6d9b64 | 69 | |
36cf20f5 RB |
70 | static void get_str8(ByteIOContext *pb, char *buf, int buf_size) |
71 | { | |
72 | get_strl(pb, buf, buf_size, get_byte(pb)); | |
de6d9b64 FB |
73 | } |
74 | ||
ba614729 RB |
75 | RMStream *ff_rm_alloc_rmstream (void) |
76 | { | |
77 | RMStream *rms = av_mallocz(sizeof(RMStream)); | |
78 | rms->curpic_num = -1; | |
79 | return rms; | |
80 | } | |
81 | ||
82 | void ff_rm_free_rmstream (RMStream *rms) | |
83 | { | |
7d204e67 RD |
84 | av_freep(&rms->videobuf); |
85 | av_freep(&rms->audiobuf); | |
ba614729 RB |
86 | } |
87 | ||
fcc995a5 | 88 | static int rm_read_audio_stream_info(AVFormatContext *s, ByteIOContext *pb, |
886e89d0 | 89 | AVStream *st, RMStream *ast, int read_all) |
c9510803 | 90 | { |
1e4668d1 | 91 | char buf[256]; |
c9510803 | 92 | uint32_t version; |
c9510803 FB |
93 | |
94 | /* ra type header */ | |
95 | version = get_be32(pb); /* version */ | |
96 | if (((version >> 16) & 0xff) == 3) { | |
1e4668d1 | 97 | int64_t startpos = url_ftell(pb); |
b9b2b8c9 | 98 | url_fskip(pb, 14); |
c9510803 FB |
99 | get_str8(pb, s->title, sizeof(s->title)); |
100 | get_str8(pb, s->author, sizeof(s->author)); | |
101 | get_str8(pb, s->copyright, sizeof(s->copyright)); | |
102 | get_str8(pb, s->comment, sizeof(s->comment)); | |
1e4668d1 | 103 | if ((startpos + (version & 0xffff)) >= url_ftell(pb) + 2) { |
76f940b2 RB |
104 | // fourcc (should always be "lpcJ") |
105 | get_byte(pb); | |
106 | get_str8(pb, buf, sizeof(buf)); | |
1e4668d1 RT |
107 | } |
108 | // Skip extra header crap (this should never happen) | |
109 | if ((startpos + (version & 0xffff)) > url_ftell(pb)) | |
110 | url_fskip(pb, (version & 0xffff) + startpos - url_ftell(pb)); | |
01f4895c MN |
111 | st->codec->sample_rate = 8000; |
112 | st->codec->channels = 1; | |
113 | st->codec->codec_type = CODEC_TYPE_AUDIO; | |
114 | st->codec->codec_id = CODEC_ID_RA_144; | |
c9510803 | 115 | } else { |
e0f7e329 | 116 | int flavor, sub_packet_h, coded_framesize, sub_packet_size; |
c9510803 FB |
117 | /* old version (4) */ |
118 | get_be32(pb); /* .ra4 */ | |
72aef198 MN |
119 | get_be32(pb); /* data size */ |
120 | get_be16(pb); /* version2 */ | |
c9510803 | 121 | get_be32(pb); /* header size */ |
72aef198 | 122 | flavor= get_be16(pb); /* add codec info / flavor */ |
ba614729 | 123 | ast->coded_framesize = coded_framesize = get_be32(pb); /* coded frame size */ |
c9510803 FB |
124 | get_be32(pb); /* ??? */ |
125 | get_be32(pb); /* ??? */ | |
126 | get_be32(pb); /* ??? */ | |
ba614729 | 127 | ast->sub_packet_h = sub_packet_h = get_be16(pb); /* 1 */ |
01f4895c | 128 | st->codec->block_align= get_be16(pb); /* frame size */ |
ba614729 | 129 | ast->sub_packet_size = sub_packet_size = get_be16(pb); /* sub packet size */ |
72aef198 | 130 | get_be16(pb); /* ??? */ |
e0f7e329 | 131 | if (((version >> 16) & 0xff) == 5) { |
127ed7b0 RB |
132 | get_be16(pb); get_be16(pb); get_be16(pb); |
133 | } | |
01f4895c | 134 | st->codec->sample_rate = get_be16(pb); |
c9510803 | 135 | get_be32(pb); |
01f4895c | 136 | st->codec->channels = get_be16(pb); |
e0f7e329 BL |
137 | if (((version >> 16) & 0xff) == 5) { |
138 | get_be32(pb); | |
b9b2b8c9 | 139 | get_buffer(pb, buf, 4); |
bb270c08 DB |
140 | buf[4] = 0; |
141 | } else { | |
e344c1ea SH |
142 | get_str8(pb, buf, sizeof(buf)); /* desc */ |
143 | get_str8(pb, buf, sizeof(buf)); /* desc */ | |
bb270c08 | 144 | } |
01f4895c | 145 | st->codec->codec_type = CODEC_TYPE_AUDIO; |
c9510803 | 146 | if (!strcmp(buf, "dnet")) { |
01f4895c | 147 | st->codec->codec_id = CODEC_ID_AC3; |
bf415121 | 148 | st->need_parsing = AVSTREAM_PARSE_FULL; |
72aef198 | 149 | } else if (!strcmp(buf, "28_8")) { |
01f4895c | 150 | st->codec->codec_id = CODEC_ID_RA_288; |
e0f7e329 | 151 | st->codec->extradata_size= 0; |
ba614729 | 152 | ast->audio_framesize = st->codec->block_align; |
e0f7e329 | 153 | st->codec->block_align = coded_framesize; |
a443a253 | 154 | |
ba614729 RB |
155 | if(ast->audio_framesize >= UINT_MAX / sub_packet_h){ |
156 | av_log(s, AV_LOG_ERROR, "ast->audio_framesize * sub_packet_h too large\n"); | |
a443a253 MN |
157 | return -1; |
158 | } | |
159 | ||
ba614729 | 160 | ast->audiobuf = av_malloc(ast->audio_framesize * sub_packet_h); |
2426bb96 | 161 | } else if ((!strcmp(buf, "cook")) || (!strcmp(buf, "atrc")) || (!strcmp(buf, "sipr"))) { |
b9b2b8c9 | 162 | int codecdata_length; |
e0f7e329 BL |
163 | get_be16(pb); get_byte(pb); |
164 | if (((version >> 16) & 0xff) == 5) | |
165 | get_byte(pb); | |
166 | codecdata_length = get_be32(pb); | |
a443a253 MN |
167 | if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ |
168 | av_log(s, AV_LOG_ERROR, "codecdata_length too large\n"); | |
169 | return -1; | |
170 | } | |
171 | ||
f23938f5 MN |
172 | if(sub_packet_size <= 0){ |
173 | av_log(s, AV_LOG_ERROR, "sub_packet_size is invalid\n"); | |
174 | return -1; | |
175 | } | |
176 | ||
10e26bc7 | 177 | if (!strcmp(buf, "cook")) st->codec->codec_id = CODEC_ID_COOK; |
2426bb96 | 178 | else if (!strcmp(buf, "sipr")) st->codec->codec_id = CODEC_ID_SIPR; |
10e26bc7 | 179 | else st->codec->codec_id = CODEC_ID_ATRAC3; |
e0f7e329 | 180 | st->codec->extradata_size= codecdata_length; |
d76319b1 | 181 | st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); |
b9b2b8c9 | 182 | get_buffer(pb, st->codec->extradata, st->codec->extradata_size); |
ba614729 RB |
183 | ast->audio_framesize = st->codec->block_align; |
184 | st->codec->block_align = ast->sub_packet_size; | |
a443a253 | 185 | |
ba614729 | 186 | if(ast->audio_framesize >= UINT_MAX / sub_packet_h){ |
a443a253 MN |
187 | av_log(s, AV_LOG_ERROR, "rm->audio_framesize * sub_packet_h too large\n"); |
188 | return -1; | |
189 | } | |
190 | ||
ba614729 | 191 | ast->audiobuf = av_malloc(ast->audio_framesize * sub_packet_h); |
a194f595 | 192 | } else if (!strcmp(buf, "raac") || !strcmp(buf, "racp")) { |
b9b2b8c9 | 193 | int codecdata_length; |
a194f595 RT |
194 | get_be16(pb); get_byte(pb); |
195 | if (((version >> 16) & 0xff) == 5) | |
196 | get_byte(pb); | |
197 | st->codec->codec_id = CODEC_ID_AAC; | |
198 | codecdata_length = get_be32(pb); | |
a9d4a6ef RT |
199 | if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ |
200 | av_log(s, AV_LOG_ERROR, "codecdata_length too large\n"); | |
201 | return -1; | |
202 | } | |
a194f595 RT |
203 | if (codecdata_length >= 1) { |
204 | st->codec->extradata_size = codecdata_length - 1; | |
205 | st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); | |
206 | get_byte(pb); | |
b9b2b8c9 | 207 | get_buffer(pb, st->codec->extradata, st->codec->extradata_size); |
a194f595 | 208 | } |
c9510803 | 209 | } else { |
01f4895c | 210 | st->codec->codec_id = CODEC_ID_NONE; |
75e61b0e | 211 | av_strlcpy(st->codec->codec_name, buf, sizeof(st->codec->codec_name)); |
c9510803 FB |
212 | } |
213 | if (read_all) { | |
214 | get_byte(pb); | |
215 | get_byte(pb); | |
216 | get_byte(pb); | |
115329f1 | 217 | |
c9510803 FB |
218 | get_str8(pb, s->title, sizeof(s->title)); |
219 | get_str8(pb, s->author, sizeof(s->author)); | |
220 | get_str8(pb, s->copyright, sizeof(s->copyright)); | |
221 | get_str8(pb, s->comment, sizeof(s->comment)); | |
222 | } | |
223 | } | |
a9d4a6ef | 224 | return 0; |
c9510803 FB |
225 | } |
226 | ||
0fd36362 | 227 | int |
fcc995a5 | 228 | ff_rm_read_mdpr_codecdata (AVFormatContext *s, ByteIOContext *pb, |
886e89d0 | 229 | AVStream *st, RMStream *rst, int codec_data_size) |
ff1463dc | 230 | { |
ff1463dc | 231 | unsigned int v; |
79d5045d | 232 | int size; |
ff1463dc RB |
233 | int64_t codec_pos; |
234 | ||
15995030 | 235 | av_set_pts_info(st, 64, 1, 1000); |
ff1463dc RB |
236 | codec_pos = url_ftell(pb); |
237 | v = get_be32(pb); | |
238 | if (v == MKTAG(0xfd, 'a', 'r', '.')) { | |
239 | /* ra type header */ | |
886e89d0 | 240 | if (rm_read_audio_stream_info(s, pb, st, rst, 0)) |
ff1463dc RB |
241 | return -1; |
242 | } else { | |
243 | int fps, fps2; | |
244 | if (get_le32(pb) != MKTAG('V', 'I', 'D', 'O')) { | |
245 | fail1: | |
246 | av_log(st->codec, AV_LOG_ERROR, "Unsupported video codec\n"); | |
247 | goto skip; | |
248 | } | |
249 | st->codec->codec_tag = get_le32(pb); | |
250 | // av_log(NULL, AV_LOG_DEBUG, "%X %X\n", st->codec->codec_tag, MKTAG('R', 'V', '2', '0')); | |
251 | if ( st->codec->codec_tag != MKTAG('R', 'V', '1', '0') | |
252 | && st->codec->codec_tag != MKTAG('R', 'V', '2', '0') | |
253 | && st->codec->codec_tag != MKTAG('R', 'V', '3', '0') | |
b93dd838 VS |
254 | && st->codec->codec_tag != MKTAG('R', 'V', '4', '0') |
255 | && st->codec->codec_tag != MKTAG('R', 'V', 'T', 'R')) | |
ff1463dc RB |
256 | goto fail1; |
257 | st->codec->width = get_be16(pb); | |
258 | st->codec->height = get_be16(pb); | |
259 | st->codec->time_base.num= 1; | |
260 | fps= get_be16(pb); | |
261 | st->codec->codec_type = CODEC_TYPE_VIDEO; | |
262 | get_be32(pb); | |
263 | fps2= get_be16(pb); | |
264 | get_be16(pb); | |
265 | ||
266 | st->codec->extradata_size= codec_data_size - (url_ftell(pb) - codec_pos); | |
267 | ||
268 | if(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)st->codec->extradata_size){ | |
269 | //check is redundant as get_buffer() will catch this | |
270 | av_log(s, AV_LOG_ERROR, "st->codec->extradata_size too large\n"); | |
271 | return -1; | |
272 | } | |
273 | st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); | |
437fd77b PI |
274 | if (!st->codec->extradata) |
275 | return AVERROR(ENOMEM); | |
ff1463dc RB |
276 | get_buffer(pb, st->codec->extradata, st->codec->extradata_size); |
277 | ||
278 | // av_log(NULL, AV_LOG_DEBUG, "fps= %d fps2= %d\n", fps, fps2); | |
279 | st->codec->time_base.den = fps * st->codec->time_base.num; | |
280 | switch(((uint8_t*)st->codec->extradata)[4]>>4){ | |
281 | case 1: st->codec->codec_id = CODEC_ID_RV10; break; | |
282 | case 2: st->codec->codec_id = CODEC_ID_RV20; break; | |
283 | case 3: st->codec->codec_id = CODEC_ID_RV30; break; | |
284 | case 4: st->codec->codec_id = CODEC_ID_RV40; break; | |
285 | default: goto fail1; | |
286 | } | |
287 | } | |
288 | ||
ff1463dc RB |
289 | skip: |
290 | /* skip codec info */ | |
291 | size = url_ftell(pb) - codec_pos; | |
292 | url_fskip(pb, codec_data_size - size); | |
293 | ||
36c9e40a | 294 | return 0; |
ff1463dc RB |
295 | } |
296 | ||
297 | ||
c9510803 FB |
298 | static int rm_read_header_old(AVFormatContext *s, AVFormatParameters *ap) |
299 | { | |
1edddc99 | 300 | RMDemuxContext *rm = s->priv_data; |
c9510803 FB |
301 | AVStream *st; |
302 | ||
303 | rm->old_format = 1; | |
304 | st = av_new_stream(s, 0); | |
305 | if (!st) | |
a9d4a6ef | 306 | return -1; |
886e89d0 RB |
307 | st->priv_data = ff_rm_alloc_rmstream(); |
308 | return rm_read_audio_stream_info(s, s->pb, st, st->priv_data, 1); | |
c9510803 FB |
309 | } |
310 | ||
de6d9b64 FB |
311 | static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap) |
312 | { | |
1edddc99 | 313 | RMDemuxContext *rm = s->priv_data; |
de6d9b64 | 314 | AVStream *st; |
899681cd | 315 | ByteIOContext *pb = s->pb; |
ff1463dc | 316 | unsigned int tag; |
07cb073b | 317 | int tag_size; |
36c32bdd | 318 | unsigned int start_time, duration; |
de6d9b64 | 319 | char buf[128]; |
5d6ef63f | 320 | int flags = 0; |
de6d9b64 | 321 | |
c9510803 FB |
322 | tag = get_le32(pb); |
323 | if (tag == MKTAG('.', 'r', 'a', 0xfd)) { | |
324 | /* very old .ra format */ | |
325 | return rm_read_header_old(s, ap); | |
326 | } else if (tag != MKTAG('.', 'R', 'M', 'F')) { | |
6f3e0b21 | 327 | return AVERROR(EIO); |
c9510803 | 328 | } |
de6d9b64 FB |
329 | |
330 | get_be32(pb); /* header size */ | |
331 | get_be16(pb); | |
332 | get_be32(pb); | |
333 | get_be32(pb); /* number of headers */ | |
115329f1 | 334 | |
de6d9b64 FB |
335 | for(;;) { |
336 | if (url_feof(pb)) | |
ccafd472 | 337 | return -1; |
de6d9b64 FB |
338 | tag = get_le32(pb); |
339 | tag_size = get_be32(pb); | |
340 | get_be16(pb); | |
341 | #if 0 | |
115329f1 | 342 | printf("tag=%c%c%c%c (%08x) size=%d\n", |
de6d9b64 FB |
343 | (tag) & 0xff, |
344 | (tag >> 8) & 0xff, | |
345 | (tag >> 16) & 0xff, | |
346 | (tag >> 24) & 0xff, | |
347 | tag, | |
348 | tag_size); | |
349 | #endif | |
9786bd4d | 350 | if (tag_size < 10 && tag != MKTAG('D', 'A', 'T', 'A')) |
ccafd472 | 351 | return -1; |
de6d9b64 FB |
352 | switch(tag) { |
353 | case MKTAG('P', 'R', 'O', 'P'): | |
354 | /* file header */ | |
355 | get_be32(pb); /* max bit rate */ | |
356 | get_be32(pb); /* avg bit rate */ | |
357 | get_be32(pb); /* max packet size */ | |
358 | get_be32(pb); /* avg packet size */ | |
359 | get_be32(pb); /* nb packets */ | |
360 | get_be32(pb); /* duration */ | |
361 | get_be32(pb); /* preroll */ | |
362 | get_be32(pb); /* index offset */ | |
363 | get_be32(pb); /* data offset */ | |
364 | get_be16(pb); /* nb streams */ | |
5d6ef63f | 365 | flags = get_be16(pb); /* flags */ |
de6d9b64 FB |
366 | break; |
367 | case MKTAG('C', 'O', 'N', 'T'): | |
36cf20f5 RB |
368 | get_str16(pb, s->title, sizeof(s->title)); |
369 | get_str16(pb, s->author, sizeof(s->author)); | |
370 | get_str16(pb, s->copyright, sizeof(s->copyright)); | |
371 | get_str16(pb, s->comment, sizeof(s->comment)); | |
de6d9b64 FB |
372 | break; |
373 | case MKTAG('M', 'D', 'P', 'R'): | |
247eadca | 374 | st = av_new_stream(s, 0); |
de6d9b64 | 375 | if (!st) |
ccafd472 | 376 | return AVERROR(ENOMEM); |
de6d9b64 FB |
377 | st->id = get_be16(pb); |
378 | get_be32(pb); /* max bit rate */ | |
01f4895c | 379 | st->codec->bit_rate = get_be32(pb); /* bit rate */ |
de6d9b64 FB |
380 | get_be32(pb); /* max packet size */ |
381 | get_be32(pb); /* avg packet size */ | |
247eadca | 382 | start_time = get_be32(pb); /* start time */ |
de6d9b64 | 383 | get_be32(pb); /* preroll */ |
247eadca | 384 | duration = get_be32(pb); /* duration */ |
c0df9d75 MN |
385 | st->start_time = start_time; |
386 | st->duration = duration; | |
de6d9b64 FB |
387 | get_str8(pb, buf, sizeof(buf)); /* desc */ |
388 | get_str8(pb, buf, sizeof(buf)); /* mimetype */ | |
01f4895c | 389 | st->codec->codec_type = CODEC_TYPE_DATA; |
886e89d0 RB |
390 | st->priv_data = ff_rm_alloc_rmstream(); |
391 | if (ff_rm_read_mdpr_codecdata(s, s->pb, st, st->priv_data, | |
392 | get_be32(pb)) < 0) | |
ff1463dc | 393 | return -1; |
de6d9b64 FB |
394 | break; |
395 | case MKTAG('D', 'A', 'T', 'A'): | |
396 | goto header_end; | |
397 | default: | |
398 | /* unknown tag: skip it */ | |
399 | url_fskip(pb, tag_size - 10); | |
400 | break; | |
401 | } | |
402 | } | |
403 | header_end: | |
404 | rm->nb_packets = get_be32(pb); /* number of packets */ | |
5d6ef63f PG |
405 | if (!rm->nb_packets && (flags & 4)) |
406 | rm->nb_packets = 3600 * 25; | |
de6d9b64 FB |
407 | get_be32(pb); /* next data header */ |
408 | return 0; | |
de6d9b64 FB |
409 | } |
410 | ||
4c2bc159 MN |
411 | static int get_num(ByteIOContext *pb, int *len) |
412 | { | |
413 | int n, n1; | |
414 | ||
415 | n = get_be16(pb); | |
416 | (*len)-=2; | |
e3052ce7 | 417 | n &= 0x7FFF; |
4c2bc159 MN |
418 | if (n >= 0x4000) { |
419 | return n - 0x4000; | |
420 | } else { | |
421 | n1 = get_be16(pb); | |
422 | (*len)-=2; | |
423 | return (n << 16) | n1; | |
424 | } | |
425 | } | |
426 | ||
c9510803 FB |
427 | /* multiple of 20 bytes for ra144 (ugly) */ |
428 | #define RAW_PACKET_SIZE 1000 | |
429 | ||
37e85dac | 430 | static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_index, int64_t *pos){ |
1edddc99 | 431 | RMDemuxContext *rm = s->priv_data; |
899681cd | 432 | ByteIOContext *pb = s->pb; |
bc17df09 MN |
433 | int len, num, res, i; |
434 | AVStream *st; | |
119cebf4 | 435 | uint32_t state=0xFFFFFFFF; |
bc17df09 MN |
436 | |
437 | while(!url_feof(pb)){ | |
fd31550d | 438 | *pos= url_ftell(pb) - 3; |
bc17df09 MN |
439 | if(rm->remaining_len > 0){ |
440 | num= rm->current_stream; | |
441 | len= rm->remaining_len; | |
442 | *timestamp = AV_NOPTS_VALUE; | |
443 | *flags= 0; | |
444 | }else{ | |
119cebf4 | 445 | state= (state<<8) + get_byte(pb); |
115329f1 | 446 | |
119cebf4 MN |
447 | if(state == MKBETAG('I', 'N', 'D', 'X')){ |
448 | len = get_be16(pb) - 6; | |
449 | if(len<0) | |
450 | continue; | |
451 | goto skip; | |
452 | } | |
115329f1 | 453 | |
119cebf4 | 454 | if(state > (unsigned)0xFFFF || state < 12) |
bc17df09 | 455 | continue; |
119cebf4 MN |
456 | len=state; |
457 | state= 0xFFFFFFFF; | |
458 | ||
bc17df09 MN |
459 | num = get_be16(pb); |
460 | *timestamp = get_be32(pb); | |
461 | res= get_byte(pb); /* reserved */ | |
462 | *flags = get_byte(pb); /* flags */ | |
37e85dac | 463 | |
115329f1 | 464 | |
bc17df09 MN |
465 | len -= 12; |
466 | } | |
467 | for(i=0;i<s->nb_streams;i++) { | |
468 | st = s->streams[i]; | |
469 | if (num == st->id) | |
470 | break; | |
471 | } | |
472 | if (i == s->nb_streams) { | |
119cebf4 | 473 | skip: |
bc17df09 MN |
474 | /* skip packet if unknown number */ |
475 | url_fskip(pb, len); | |
476 | rm->remaining_len -= len; | |
477 | continue; | |
478 | } | |
479 | *stream_index= i; | |
115329f1 | 480 | |
bc17df09 MN |
481 | return len; |
482 | } | |
483 | return -1; | |
484 | } | |
485 | ||
fcc995a5 | 486 | static int rm_assemble_video_frame(AVFormatContext *s, ByteIOContext *pb, |
ba614729 RB |
487 | RMDemuxContext *rm, RMStream *vst, |
488 | AVPacket *pkt, int len) | |
383b123e | 489 | { |
383b123e KS |
490 | int hdr, seq, pic_num, len2, pos; |
491 | int type; | |
383b123e KS |
492 | |
493 | hdr = get_byte(pb); len--; | |
494 | type = hdr >> 6; | |
495 | switch(type){ | |
496 | case 0: // slice | |
497 | case 2: // last slice | |
498 | seq = get_byte(pb); len--; | |
499 | len2 = get_num(pb, &len); | |
500 | pos = get_num(pb, &len); | |
501 | pic_num = get_byte(pb); len--; | |
502 | rm->remaining_len = len; | |
503 | break; | |
504 | case 1: //whole frame | |
505 | seq = get_byte(pb); len--; | |
506 | if(av_new_packet(pkt, len + 9) < 0) | |
507 | return AVERROR(EIO); | |
508 | pkt->data[0] = 0; | |
509 | AV_WL32(pkt->data + 1, 1); | |
510 | AV_WL32(pkt->data + 5, 0); | |
511 | get_buffer(pb, pkt->data + 9, len); | |
512 | rm->remaining_len = 0; | |
513 | return 0; | |
514 | case 3: //frame as a part of packet | |
515 | len2 = get_num(pb, &len); | |
516 | pos = get_num(pb, &len); | |
517 | pic_num = get_byte(pb); len--; | |
518 | rm->remaining_len = len - len2; | |
519 | if(av_new_packet(pkt, len2 + 9) < 0) | |
520 | return AVERROR(EIO); | |
521 | pkt->data[0] = 0; | |
522 | AV_WL32(pkt->data + 1, 1); | |
523 | AV_WL32(pkt->data + 5, 0); | |
524 | get_buffer(pb, pkt->data + 9, len2); | |
525 | return 0; | |
526 | } | |
527 | //now we have to deal with single slice | |
528 | ||
ba614729 RB |
529 | if((seq & 0x7F) == 1 || vst->curpic_num != pic_num){ |
530 | vst->slices = ((hdr & 0x3F) << 1) + 1; | |
531 | vst->videobufsize = len2 + 8*vst->slices + 1; | |
532 | av_free(vst->videobuf); | |
533 | if(!(vst->videobuf = av_malloc(vst->videobufsize))) | |
52537534 | 534 | return AVERROR(ENOMEM); |
ba614729 RB |
535 | vst->videobufpos = 8*vst->slices + 1; |
536 | vst->cur_slice = 0; | |
537 | vst->curpic_num = pic_num; | |
538 | vst->pktpos = url_ftell(pb); | |
383b123e | 539 | } |
e35033e6 | 540 | if(type == 2) |
383b123e | 541 | len = FFMIN(len, pos); |
383b123e | 542 | |
ba614729 | 543 | if(++vst->cur_slice > vst->slices) |
383b123e | 544 | return 1; |
ba614729 RB |
545 | AV_WL32(vst->videobuf - 7 + 8*vst->cur_slice, 1); |
546 | AV_WL32(vst->videobuf - 3 + 8*vst->cur_slice, vst->videobufpos - 8*vst->slices - 1); | |
547 | if(vst->videobufpos + len > vst->videobufsize) | |
383b123e | 548 | return 1; |
ba614729 | 549 | if (get_buffer(pb, vst->videobuf + vst->videobufpos, len) != len) |
383b123e | 550 | return AVERROR(EIO); |
ba614729 | 551 | vst->videobufpos += len; |
383b123e KS |
552 | rm->remaining_len-= len; |
553 | ||
ba614729 RB |
554 | if(type == 2 || (vst->videobufpos) == vst->videobufsize){ |
555 | vst->videobuf[0] = vst->cur_slice-1; | |
556 | if(av_new_packet(pkt, vst->videobufpos - 8*(vst->slices - vst->cur_slice)) < 0) | |
383b123e | 557 | return AVERROR(ENOMEM); |
ba614729 RB |
558 | memcpy(pkt->data, vst->videobuf, 1 + 8*vst->cur_slice); |
559 | memcpy(pkt->data + 1 + 8*vst->cur_slice, vst->videobuf + 1 + 8*vst->slices, | |
560 | vst->videobufpos - 1 - 8*vst->slices); | |
d447fc31 | 561 | pkt->pts = AV_NOPTS_VALUE; |
ba614729 | 562 | pkt->pos = vst->pktpos; |
383b123e KS |
563 | return 0; |
564 | } | |
565 | ||
566 | return 1; | |
567 | } | |
568 | ||
5c470b91 RB |
569 | static inline void |
570 | rm_ac3_swap_bytes (AVStream *st, AVPacket *pkt) | |
571 | { | |
572 | uint8_t *ptr; | |
573 | int j; | |
574 | ||
575 | if (st->codec->codec_id == CODEC_ID_AC3) { | |
576 | ptr = pkt->data; | |
577 | for (j=0;j<pkt->size;j+=2) { | |
578 | FFSWAP(int, ptr[0], ptr[1]); | |
579 | ptr += 2; | |
580 | } | |
581 | } | |
582 | } | |
583 | ||
0fd36362 | 584 | int |
fcc995a5 | 585 | ff_rm_parse_packet (AVFormatContext *s, ByteIOContext *pb, |
886e89d0 | 586 | AVStream *st, RMStream *ast, int len, AVPacket *pkt, |
afd302fa RB |
587 | int *seq, int *flags, int64_t *timestamp) |
588 | { | |
1edddc99 | 589 | RMDemuxContext *rm = s->priv_data; |
afd302fa RB |
590 | |
591 | if (st->codec->codec_type == CODEC_TYPE_VIDEO) { | |
592 | rm->current_stream= st->id; | |
51d6852f | 593 | if(rm_assemble_video_frame(s, pb, rm, ast, pkt, len)) |
afd302fa RB |
594 | return -1; //got partial frame |
595 | } else if (st->codec->codec_type == CODEC_TYPE_AUDIO) { | |
596 | if ((st->codec->codec_id == CODEC_ID_RA_288) || | |
597 | (st->codec->codec_id == CODEC_ID_COOK) || | |
2426bb96 BL |
598 | (st->codec->codec_id == CODEC_ID_ATRAC3) || |
599 | (st->codec->codec_id == CODEC_ID_SIPR)) { | |
afd302fa | 600 | int x; |
ba614729 RB |
601 | int sps = ast->sub_packet_size; |
602 | int cfs = ast->coded_framesize; | |
603 | int h = ast->sub_packet_h; | |
604 | int y = ast->sub_packet_cnt; | |
605 | int w = ast->audio_framesize; | |
afd302fa RB |
606 | |
607 | if (*flags & 2) | |
ba614729 | 608 | y = ast->sub_packet_cnt = 0; |
afd302fa | 609 | if (!y) |
ba614729 | 610 | ast->audiotimestamp = *timestamp; |
afd302fa RB |
611 | |
612 | switch(st->codec->codec_id) { | |
613 | case CODEC_ID_RA_288: | |
614 | for (x = 0; x < h/2; x++) | |
ba614729 | 615 | get_buffer(pb, ast->audiobuf+x*2*w+y*cfs, cfs); |
afd302fa RB |
616 | break; |
617 | case CODEC_ID_ATRAC3: | |
618 | case CODEC_ID_COOK: | |
619 | for (x = 0; x < w/sps; x++) | |
ba614729 | 620 | get_buffer(pb, ast->audiobuf+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), sps); |
afd302fa RB |
621 | break; |
622 | } | |
623 | ||
ba614729 | 624 | if (++(ast->sub_packet_cnt) < h) |
afd302fa RB |
625 | return -1; |
626 | else { | |
ba614729 | 627 | ast->sub_packet_cnt = 0; |
afd302fa RB |
628 | rm->audio_stream_num = st->index; |
629 | rm->audio_pkt_cnt = h * w / st->codec->block_align - 1; | |
630 | // Release first audio packet | |
631 | av_new_packet(pkt, st->codec->block_align); | |
ba614729 RB |
632 | memcpy(pkt->data, ast->audiobuf, st->codec->block_align); |
633 | *timestamp = ast->audiotimestamp; | |
afd302fa RB |
634 | *flags = 2; // Mark first packet as keyframe |
635 | } | |
636 | } else if (st->codec->codec_id == CODEC_ID_AAC) { | |
637 | int x; | |
638 | rm->audio_stream_num = st->index; | |
ba614729 RB |
639 | ast->sub_packet_cnt = (get_be16(pb) & 0xf0) >> 4; |
640 | if (ast->sub_packet_cnt) { | |
641 | for (x = 0; x < ast->sub_packet_cnt; x++) | |
642 | ast->sub_packet_lengths[x] = get_be16(pb); | |
afd302fa | 643 | // Release first audio packet |
ba614729 RB |
644 | rm->audio_pkt_cnt = ast->sub_packet_cnt - 1; |
645 | av_get_packet(pb, pkt, ast->sub_packet_lengths[0]); | |
afd302fa RB |
646 | *flags = 2; // Mark first packet as keyframe |
647 | } | |
badbe09a | 648 | } else { |
afd302fa | 649 | av_get_packet(pb, pkt, len); |
e29378ff | 650 | rm_ac3_swap_bytes(st, pkt); |
badbe09a | 651 | } |
afd302fa RB |
652 | } else |
653 | av_get_packet(pb, pkt, len); | |
654 | ||
655 | if( (st->discard >= AVDISCARD_NONKEY && !(*flags&2)) | |
656 | || st->discard >= AVDISCARD_ALL){ | |
657 | av_free_packet(pkt); | |
658 | return -1; | |
659 | } | |
660 | ||
661 | pkt->stream_index = st->index; | |
662 | ||
663 | #if 0 | |
664 | if (st->codec->codec_type == CODEC_TYPE_VIDEO) { | |
665 | if(st->codec->codec_id == CODEC_ID_RV20){ | |
666 | int seq= 128*(pkt->data[2]&0x7F) + (pkt->data[3]>>1); | |
667 | av_log(NULL, AV_LOG_DEBUG, "%d %"PRId64" %d\n", *timestamp, *timestamp*512LL/25, seq); | |
668 | ||
669 | seq |= (*timestamp&~0x3FFF); | |
670 | if(seq - *timestamp > 0x2000) seq -= 0x4000; | |
671 | if(seq - *timestamp < -0x2000) seq += 0x4000; | |
672 | } | |
673 | } | |
674 | #endif | |
675 | ||
676 | pkt->pts= *timestamp; | |
677 | if (*flags & 2) | |
678 | pkt->flags |= PKT_FLAG_KEY; | |
679 | ||
a15ebf34 | 680 | return st->codec->codec_type == CODEC_TYPE_AUDIO ? rm->audio_pkt_cnt : 0; |
afd302fa RB |
681 | } |
682 | ||
a9f84821 | 683 | int |
fcc995a5 | 684 | ff_rm_retrieve_cache (AVFormatContext *s, ByteIOContext *pb, |
886e89d0 | 685 | AVStream *st, RMStream *ast, AVPacket *pkt) |
d4d1b5fb | 686 | { |
1edddc99 | 687 | RMDemuxContext *rm = s->priv_data; |
d4d1b5fb RB |
688 | |
689 | assert (rm->audio_pkt_cnt > 0); | |
690 | ||
691 | if (st->codec->codec_id == CODEC_ID_AAC) | |
ba614729 | 692 | av_get_packet(pb, pkt, ast->sub_packet_lengths[ast->sub_packet_cnt - rm->audio_pkt_cnt]); |
d4d1b5fb RB |
693 | else { |
694 | av_new_packet(pkt, st->codec->block_align); | |
ba614729 RB |
695 | memcpy(pkt->data, ast->audiobuf + st->codec->block_align * |
696 | (ast->sub_packet_h * ast->audio_framesize / st->codec->block_align - rm->audio_pkt_cnt), | |
d4d1b5fb RB |
697 | st->codec->block_align); |
698 | } | |
699 | rm->audio_pkt_cnt--; | |
700 | pkt->flags = 0; | |
701 | pkt->stream_index = st->index; | |
a9f84821 RB |
702 | |
703 | return rm->audio_pkt_cnt; | |
d4d1b5fb RB |
704 | } |
705 | ||
de6d9b64 FB |
706 | static int rm_read_packet(AVFormatContext *s, AVPacket *pkt) |
707 | { | |
1edddc99 | 708 | RMDemuxContext *rm = s->priv_data; |
899681cd | 709 | ByteIOContext *pb = s->pb; |
de6d9b64 | 710 | AVStream *st; |
5c470b91 | 711 | int i, len; |
37e85dac | 712 | int64_t timestamp, pos; |
bc17df09 | 713 | int flags; |
de6d9b64 | 714 | |
c69e7914 | 715 | if (rm->audio_pkt_cnt) { |
e0f7e329 BL |
716 | // If there are queued audio packet return them first |
717 | st = s->streams[rm->audio_stream_num]; | |
886e89d0 | 718 | ff_rm_retrieve_cache(s, s->pb, st, st->priv_data, pkt); |
c69e7914 | 719 | } else if (rm->old_format) { |
ba614729 RB |
720 | RMStream *ast; |
721 | ||
c69e7914 | 722 | st = s->streams[0]; |
ba614729 | 723 | ast = st->priv_data; |
c69e7914 RT |
724 | if (st->codec->codec_id == CODEC_ID_RA_288) { |
725 | int x, y; | |
726 | ||
ba614729 RB |
727 | for (y = 0; y < ast->sub_packet_h; y++) |
728 | for (x = 0; x < ast->sub_packet_h/2; x++) | |
729 | if (get_buffer(pb, ast->audiobuf+x*2*ast->audio_framesize+y*ast->coded_framesize, ast->coded_framesize) <= 0) | |
6f3e0b21 | 730 | return AVERROR(EIO); |
c69e7914 | 731 | rm->audio_stream_num = 0; |
ba614729 | 732 | rm->audio_pkt_cnt = ast->sub_packet_h * ast->audio_framesize / st->codec->block_align - 1; |
c69e7914 RT |
733 | // Release first audio packet |
734 | av_new_packet(pkt, st->codec->block_align); | |
ba614729 | 735 | memcpy(pkt->data, ast->audiobuf, st->codec->block_align); |
c69e7914 RT |
736 | pkt->flags |= PKT_FLAG_KEY; // Mark first packet as keyframe |
737 | pkt->stream_index = 0; | |
738 | } else { | |
739 | /* just read raw bytes */ | |
740 | len = RAW_PACKET_SIZE; | |
741 | len= av_get_packet(pb, pkt, len); | |
742 | pkt->stream_index = 0; | |
743 | if (len <= 0) { | |
6f3e0b21 | 744 | return AVERROR(EIO); |
c69e7914 RT |
745 | } |
746 | pkt->size = len; | |
747 | } | |
e29378ff | 748 | rm_ac3_swap_bytes(st, pkt); |
c9510803 | 749 | } else { |
37e85dac | 750 | int seq=1; |
b9866ebc | 751 | resync: |
37e85dac | 752 | len=sync(s, ×tamp, &flags, &i, &pos); |
bc17df09 | 753 | if(len<0) |
6f3e0b21 | 754 | return AVERROR(EIO); |
bc17df09 MN |
755 | st = s->streams[i]; |
756 | ||
886e89d0 RB |
757 | if (ff_rm_parse_packet (s, s->pb, st, st->priv_data, len, pkt, |
758 | &seq, &flags, ×tamp) < 0) | |
b9866ebc | 759 | goto resync; |
d880240e | 760 | |
9b41eb37 | 761 | if((flags&2) && (seq&0x7F) == 1) |
8f8fae80 | 762 | av_add_index_entry(st, pos, timestamp, 0, 0, AVINDEX_KEYFRAME); |
5d6ef63f PG |
763 | } |
764 | ||
de6d9b64 FB |
765 | return 0; |
766 | } | |
767 | ||
768 | static int rm_read_close(AVFormatContext *s) | |
769 | { | |
ba614729 RB |
770 | int i; |
771 | ||
772 | for (i=0;i<s->nb_streams;i++) | |
773 | ff_rm_free_rmstream(s->streams[i]->priv_data); | |
e0f7e329 | 774 | |
de6d9b64 FB |
775 | return 0; |
776 | } | |
777 | ||
c9a65ca8 FB |
778 | static int rm_probe(AVProbeData *p) |
779 | { | |
780 | /* check file header */ | |
c9510803 FB |
781 | if ((p->buf[0] == '.' && p->buf[1] == 'R' && |
782 | p->buf[2] == 'M' && p->buf[3] == 'F' && | |
783 | p->buf[4] == 0 && p->buf[5] == 0) || | |
784 | (p->buf[0] == '.' && p->buf[1] == 'r' && | |
785 | p->buf[2] == 'a' && p->buf[3] == 0xfd)) | |
c9a65ca8 FB |
786 | return AVPROBE_SCORE_MAX; |
787 | else | |
788 | return 0; | |
789 | } | |
790 | ||
115329f1 | 791 | static int64_t rm_read_dts(AVFormatContext *s, int stream_index, |
bc17df09 MN |
792 | int64_t *ppos, int64_t pos_limit) |
793 | { | |
1edddc99 | 794 | RMDemuxContext *rm = s->priv_data; |
bc17df09 | 795 | int64_t pos, dts; |
37e85dac | 796 | int stream_index2, flags, len, h; |
bc17df09 MN |
797 | |
798 | pos = *ppos; | |
115329f1 | 799 | |
bc17df09 MN |
800 | if(rm->old_format) |
801 | return AV_NOPTS_VALUE; | |
802 | ||
899681cd | 803 | url_fseek(s->pb, pos, SEEK_SET); |
bc17df09 MN |
804 | rm->remaining_len=0; |
805 | for(;;){ | |
37e85dac MN |
806 | int seq=1; |
807 | AVStream *st; | |
808 | ||
809 | len=sync(s, &dts, &flags, &stream_index2, &pos); | |
bc17df09 MN |
810 | if(len<0) |
811 | return AV_NOPTS_VALUE; | |
37e85dac MN |
812 | |
813 | st = s->streams[stream_index2]; | |
01f4895c | 814 | if (st->codec->codec_type == CODEC_TYPE_VIDEO) { |
899681cd | 815 | h= get_byte(s->pb); len--; |
37e85dac | 816 | if(!(h & 0x40)){ |
899681cd | 817 | seq = get_byte(s->pb); len--; |
bc17df09 MN |
818 | } |
819 | } | |
115329f1 | 820 | |
37e85dac | 821 | if((flags&2) && (seq&0x7F) == 1){ |
949b1a13 | 822 | // av_log(s, AV_LOG_DEBUG, "%d %d-%d %"PRId64" %d\n", flags, stream_index2, stream_index, dts, seq); |
30a43f2d | 823 | av_add_index_entry(st, pos, dts, 0, 0, AVINDEX_KEYFRAME); |
37e85dac MN |
824 | if(stream_index2 == stream_index) |
825 | break; | |
826 | } | |
827 | ||
899681cd | 828 | url_fskip(s->pb, len); |
bc17df09 MN |
829 | } |
830 | *ppos = pos; | |
831 | return dts; | |
832 | } | |
833 | ||
ff70e601 | 834 | AVInputFormat rm_demuxer = { |
c9a65ca8 | 835 | "rm", |
bde15e74 | 836 | NULL_IF_CONFIG_SMALL("RM format"), |
1edddc99 | 837 | sizeof(RMDemuxContext), |
c9a65ca8 FB |
838 | rm_probe, |
839 | rm_read_header, | |
840 | rm_read_packet, | |
841 | rm_read_close, | |
bc17df09 MN |
842 | NULL, |
843 | rm_read_dts, | |
c9a65ca8 | 844 | }; |
ff13ba92 RB |
845 | |
846 | AVInputFormat rdt_demuxer = { | |
847 | "rdt", | |
848 | NULL_IF_CONFIG_SMALL("RDT demuxer"), | |
1edddc99 | 849 | sizeof(RMDemuxContext), |
ff13ba92 RB |
850 | NULL, NULL, NULL, rm_read_close, NULL, NULL |
851 | }; |