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