3777
|
1 /*
|
|
2 Real parser & demuxer
|
|
3
|
|
4 (C) Alex Beregszaszi <alex@naxine.org>
|
|
5
|
|
6 Based on FFmpeg's libav/rm.c.
|
|
7 */
|
|
8
|
3788
|
9 /*
|
|
10 Some codecs for Real (from Mike Melanson):
|
|
11
|
|
12 RV10: As has been mentioned, H.263-based; not an unreasonable guess
|
|
13 RV20: RealVideo 2.0, nothing known
|
|
14 RV30: RealVideo 3.0,nothing known, but I don't believe I've ever seen any
|
|
15 media encoded with it
|
|
16 DNET: apparently one of their original audio codecs, to be used with music
|
|
17 SIPR: SiprNet, based on ACELP, and is great for compressing voice
|
|
18 COKR(?): Cooker, the fabled G2 audio codec
|
3795
|
19
|
|
20 New infos:
|
|
21
|
|
22 Audio codecs: (supported by RealPlayer8 for Linux)
|
|
23 ATRC - RealAudio 8 (ATRAC3)
|
|
24 COOK - RealAudio G2
|
|
25 DNET - RealAudio 3.0
|
|
26 SIPR - SiproLab's audio codec
|
|
27
|
|
28 Video codecs: (supported by RealPlayer8 for Linux)
|
|
29 RV10
|
|
30 RV20
|
|
31 RV30
|
3788
|
32 */
|
|
33
|
3777
|
34 #include <stdio.h>
|
|
35 #include <stdlib.h>
|
|
36 #include <unistd.h>
|
|
37
|
|
38 #include "config.h"
|
|
39 #include "mp_msg.h"
|
|
40 #include "help_mp.h"
|
|
41
|
|
42 #include "stream.h"
|
|
43 #include "demuxer.h"
|
|
44 #include "stheader.h"
|
|
45 #include "bswap.h"
|
|
46
|
|
47 #define MKTAG(a, b, c, d) (a | (b << 8) | (c << 16) | (d << 24))
|
|
48
|
|
49 #define MAX_STREAMS 10
|
|
50
|
|
51 typedef struct {
|
3795
|
52 int data_chunk_offset; /* i think for seeking */
|
3777
|
53 int num_of_packets;
|
|
54 int last_a_stream;
|
|
55 int a_streams[MAX_STREAMS];
|
|
56 int last_v_stream;
|
|
57 int v_streams[MAX_STREAMS];
|
|
58 } real_priv_t;
|
|
59
|
|
60 static void get_str(int isbyte, demuxer_t *demuxer, char *buf, int buf_size)
|
|
61 {
|
|
62 int len, i;
|
|
63 char *q;
|
|
64
|
|
65 if (isbyte)
|
|
66 len = stream_read_char(demuxer->stream);
|
|
67 else
|
|
68 len = stream_read_word(demuxer->stream);
|
|
69 #if 1
|
|
70 q = buf;
|
|
71 for (i = 0; i < len; i++)
|
|
72 if (i < (buf_size - 1))
|
|
73 *q++ = stream_read_char(demuxer->stream);
|
|
74 *q = 0;
|
|
75 #else
|
|
76 stream_read(demuxer->stream, buf, buf_size);
|
|
77 #endif
|
|
78 }
|
|
79
|
|
80 static void skip_str(int isbyte, demuxer_t *demuxer)
|
|
81 {
|
|
82 int len;
|
|
83
|
|
84 if (isbyte)
|
|
85 len = stream_read_char(demuxer->stream);
|
|
86 else
|
|
87 len = stream_read_word(demuxer->stream);
|
|
88
|
|
89 stream_skip(demuxer->stream, len);
|
|
90
|
|
91 printf("skip_str: %d bytes skipped\n", len);
|
|
92 }
|
|
93
|
3795
|
94 int real_check_file(demuxer_t* demuxer)
|
|
95 {
|
3777
|
96 real_priv_t *priv;
|
|
97 int c;
|
|
98
|
|
99 mp_msg(MSGT_DEMUX,MSGL_V,"Checking for REAL\n");
|
|
100
|
|
101 c = stream_read_dword_le(demuxer->stream);
|
|
102 if (c == -256)
|
|
103 return 0; /* EOF */
|
|
104 if (c != MKTAG('.', 'R', 'M', 'F'))
|
|
105 return 0; /* bad magic */
|
|
106
|
|
107 priv = malloc(sizeof(real_priv_t));
|
|
108 memset(priv, 0, sizeof(real_priv_t));
|
|
109 demuxer->priv = priv;
|
|
110
|
|
111 return 1;
|
|
112 }
|
|
113
|
|
114 // return value:
|
|
115 // 0 = EOF or no stream found
|
|
116 // 1 = successfully read a packet
|
|
117 int demux_real_fill_buffer(demuxer_t *demuxer)
|
|
118 {
|
|
119 real_priv_t *priv = demuxer->priv;
|
|
120 demux_stream_t *ds = NULL;
|
|
121 int len;
|
|
122 int timestamp;
|
|
123 int stream_id;
|
|
124 int i;
|
3795
|
125 int flags;
|
3777
|
126
|
|
127 // printf("num_of_packets: %d\n", priv->num_of_packets);
|
|
128
|
|
129 loop:
|
|
130 if (priv->num_of_packets == 0)
|
|
131 return 0; /* EOF */
|
3795
|
132 stream_skip(demuxer->stream, 2); /* version */
|
3777
|
133 len = stream_read_word(demuxer->stream);
|
|
134 if (len == -256) /* EOF */
|
|
135 return 0;
|
|
136 if (len < 12)
|
|
137 {
|
|
138 printf("bad packet len (%d)\n", len);
|
|
139 stream_skip(demuxer->stream, len);
|
|
140 goto loop;
|
|
141 }
|
|
142 stream_id = stream_read_word(demuxer->stream);
|
|
143 timestamp = stream_read_dword(demuxer->stream);
|
|
144
|
|
145 stream_skip(demuxer->stream, 1); /* reserved */
|
3795
|
146 flags = stream_read_char(demuxer->stream);
|
|
147 /* flags: */
|
|
148 /* 0x2 - keyframe */
|
|
149
|
|
150 printf("packet#%d: len: %d, stream_id: %d, timestamp: %d, flags: %x\n",
|
|
151 priv->num_of_packets, len, stream_id, timestamp, flags);
|
3777
|
152
|
|
153 priv->num_of_packets--;
|
|
154 len -= 12;
|
|
155
|
|
156 /* check if stream_id is audio stream */
|
|
157 for (i = 0; i < priv->last_a_stream; i++)
|
|
158 {
|
|
159 if (priv->a_streams[i] == stream_id)
|
|
160 {
|
|
161 // printf("packet is audio (id: %d)\n", stream_id);
|
|
162 ds = demuxer->audio; /* FIXME */
|
|
163 break;
|
|
164 }
|
|
165 }
|
|
166 /* check if stream_id is video stream */
|
|
167 for (i = 0; i < priv->last_v_stream; i++)
|
|
168 {
|
|
169 if (priv->v_streams[i] == stream_id)
|
|
170 {
|
|
171 // printf("packet is video (id: %d)\n", stream_id);
|
|
172 ds = demuxer->video; /* FIXME */
|
|
173 break;
|
|
174 }
|
|
175 }
|
|
176
|
|
177 /* id not found */
|
|
178 if (ds == NULL)
|
|
179 {
|
|
180 printf("unknown stream id (%d)\n", stream_id);
|
|
181 stream_skip(demuxer->stream, len);
|
|
182 goto loop;
|
|
183 }
|
|
184
|
|
185 demuxer->filepos = stream_tell(demuxer->stream);
|
3795
|
186 ds_read_packet(ds, demuxer->stream, len, timestamp/90000.0f,
|
|
187 demuxer->filepos, (flags & 0x2) ? 0x10 : 0);
|
3777
|
188
|
|
189 return 1;
|
|
190 }
|
|
191
|
|
192 void demux_open_real(demuxer_t* demuxer)
|
|
193 {
|
|
194 real_priv_t* priv = demuxer->priv;
|
|
195 int num_of_headers;
|
|
196 int i;
|
|
197
|
|
198 stream_skip(demuxer->stream, 4); /* header size */
|
|
199 stream_skip(demuxer->stream, 2);
|
|
200 stream_skip(demuxer->stream, 4);
|
|
201 num_of_headers = stream_read_dword(demuxer->stream);
|
|
202 // stream_skip(demuxer->stream, 4); /* number of headers */
|
|
203
|
|
204 /* parse chunks */
|
|
205 for (i = 1; i < num_of_headers; i++)
|
|
206 {
|
|
207 int chunk, chunk_size;
|
|
208
|
|
209 chunk = stream_read_dword_le(demuxer->stream);
|
|
210 chunk_size = stream_read_dword(demuxer->stream);
|
|
211
|
|
212 stream_skip(demuxer->stream, 2);
|
|
213
|
|
214 if (chunk_size < 10)
|
|
215 goto fail;
|
|
216
|
|
217 printf("Chunk: %.4s (size: %d)\n",
|
|
218 (char *)&chunk, chunk_size);
|
|
219
|
|
220 switch(chunk)
|
|
221 {
|
|
222 case MKTAG('P', 'R', 'O', 'P'):
|
3795
|
223 // printf("Properties chunk\n");
|
3777
|
224 stream_skip(demuxer->stream, 4); /* max bitrate */
|
|
225 stream_skip(demuxer->stream, 4); /* avg bitrate */
|
|
226 stream_skip(demuxer->stream, 4); /* max packet size */
|
|
227 stream_skip(demuxer->stream, 4); /* avg packet size */
|
|
228 stream_skip(demuxer->stream, 4); /* nb packets */
|
|
229 stream_skip(demuxer->stream, 4); /* duration */
|
|
230 stream_skip(demuxer->stream, 4); /* preroll */
|
|
231 stream_skip(demuxer->stream, 4); /* index offset */
|
3795
|
232 // stream_skip(demuxer->stream, 4); /* data offset */
|
|
233 priv->data_chunk_offset = stream_read_dword(demuxer->stream)+10;
|
|
234 printf("Data chunk offset: 0x%x\n", priv->data_chunk_offset);
|
3777
|
235 stream_skip(demuxer->stream, 2); /* nb streams */
|
3795
|
236 #if 0
|
3777
|
237 stream_skip(demuxer->stream, 2); /* flags */
|
3795
|
238 #else
|
|
239 {
|
|
240 int flags = stream_read_word(demuxer->stream);
|
|
241 printf("Flags (%x): ", flags);
|
|
242 if (flags & 0x1)
|
|
243 printf("[save allowed] ");
|
|
244 if (flags & 0x2)
|
|
245 printf("[perfect play (?)] ");
|
|
246 if (flags & 0x4)
|
|
247 printf("[live broadcast] ");
|
|
248 printf("\n");
|
|
249 }
|
|
250 #endif
|
3777
|
251 break;
|
|
252 case MKTAG('C', 'O', 'N', 'T'):
|
3788
|
253 {
|
|
254 char *buf;
|
|
255 int len;
|
|
256
|
3795
|
257 // printf("Broadcasting informations (title, author, copyright, comment)\n");
|
3788
|
258
|
|
259 len = stream_read_word(demuxer->stream);
|
|
260 if (len > 0)
|
|
261 {
|
|
262 buf = malloc(len+1);
|
|
263 stream_read(demuxer->stream, buf, len);
|
|
264 demux_info_add(demuxer, "name", buf);
|
|
265 free(buf);
|
|
266 }
|
|
267
|
|
268 len = stream_read_word(demuxer->stream);
|
|
269 if (len > 0)
|
|
270 {
|
|
271 buf = malloc(len+1);
|
|
272 stream_read(demuxer->stream, buf, len);
|
|
273 demux_info_add(demuxer, "author", buf);
|
|
274 free(buf);
|
|
275 }
|
|
276
|
|
277 len = stream_read_word(demuxer->stream);
|
|
278 if (len > 0)
|
|
279 {
|
|
280 buf = malloc(len+1);
|
|
281 stream_read(demuxer->stream, buf, len);
|
|
282 demux_info_add(demuxer, "copyright", buf);
|
|
283 free(buf);
|
|
284 }
|
|
285
|
|
286 len = stream_read_word(demuxer->stream);
|
|
287 if (len > 0)
|
|
288 {
|
|
289 buf = malloc(len+1);
|
|
290 stream_read(demuxer->stream, buf, len);
|
|
291 demux_info_add(demuxer, "comment", buf);
|
|
292 free(buf);
|
|
293 }
|
|
294
|
|
295 // skip_str(0, demuxer); /* title */
|
|
296 // skip_str(0, demuxer); /* author */
|
|
297 // skip_str(0, demuxer); /* copyright */
|
|
298 // skip_str(0, demuxer); /* comment */
|
3777
|
299 break;
|
3788
|
300 }
|
3777
|
301 case MKTAG('M', 'D', 'P', 'R'):
|
|
302 {
|
|
303 /* new stream */
|
|
304 int stream_id;
|
|
305 int bitrate;
|
|
306 int codec_data_size;
|
|
307 int codec_pos;
|
3795
|
308 int tmp;
|
3777
|
309
|
|
310 stream_id = stream_read_word(demuxer->stream);
|
|
311 printf("Found new stream (id: %d)\n", stream_id);
|
|
312
|
|
313 stream_skip(demuxer->stream, 4); /* max bitrate */
|
|
314 bitrate = stream_read_dword(demuxer->stream); /* bitrate */
|
|
315 stream_skip(demuxer->stream, 4); /* max packet size */
|
|
316 stream_skip(demuxer->stream, 4); /* avg packet size */
|
|
317 stream_skip(demuxer->stream, 4); /* start time */
|
|
318 stream_skip(demuxer->stream, 4); /* preroll */
|
|
319 stream_skip(demuxer->stream, 4); /* duration */
|
|
320
|
|
321 skip_str(1, demuxer); /* stream description */
|
|
322 skip_str(1, demuxer); /* mimetype */
|
|
323
|
|
324 codec_data_size = stream_read_dword(demuxer->stream);
|
|
325 codec_pos = stream_tell(demuxer->stream);
|
|
326
|
3795
|
327 tmp = stream_read_dword(demuxer->stream);
|
|
328 if (tmp == MKTAG(0xfd, 'a', 'r', '.')) /* audio header */
|
3777
|
329 {
|
|
330 sh_audio_t *sh = new_sh_audio(demuxer, stream_id);
|
3795
|
331 char buf[128]; /* for codec name */
|
|
332 int frame_size;
|
3777
|
333
|
|
334 printf("Found audio stream!\n");
|
3788
|
335 stream_skip(demuxer->stream, 2); /* version (4 or 5) */
|
|
336 stream_skip(demuxer->stream, 2);
|
|
337 stream_skip(demuxer->stream, 4); /* .ra4 or .ra5 */
|
3777
|
338 stream_skip(demuxer->stream, 4);
|
3788
|
339 stream_skip(demuxer->stream, 2); /* version (4 or 5) */
|
3777
|
340 stream_skip(demuxer->stream, 4); /* header size */
|
|
341 stream_skip(demuxer->stream, 2); /* add codec info */
|
|
342 stream_skip(demuxer->stream, 4); /* coded frame size */
|
|
343 stream_skip(demuxer->stream, 4);
|
|
344 stream_skip(demuxer->stream, 4);
|
|
345 stream_skip(demuxer->stream, 4);
|
|
346 stream_skip(demuxer->stream, 2); /* 1 */
|
3795
|
347 // stream_skip(demuxer->stream, 2); /* coded frame size */
|
|
348 frame_size = stream_read_word(demuxer->stream);
|
|
349 printf("frame_size: %d\n", frame_size);
|
3777
|
350 stream_skip(demuxer->stream, 4);
|
|
351
|
|
352 sh->samplerate = stream_read_word(demuxer->stream);
|
|
353 stream_skip(demuxer->stream, 4);
|
|
354 sh->channels = stream_read_word(demuxer->stream);
|
|
355
|
3795
|
356 /* Desc #1 */
|
|
357 skip_str(1, demuxer);
|
|
358 /* Desc #2 */
|
|
359 get_str(1, demuxer, buf, sizeof(buf));
|
3777
|
360
|
3795
|
361 tmp = 1; /* supported audio codec */
|
|
362 switch (MKTAG(buf[0], buf[1], buf[2], buf[3]))
|
|
363 {
|
|
364 case MKTAG('a', 't', 'r', 'c'):
|
|
365 break;
|
|
366 case MKTAG('d', 'n', 'e', 't'):
|
|
367 printf("Audio: DNET -> AC3\n");
|
|
368 sh->format = 0x2000;
|
|
369 break;
|
|
370 case MKTAG('s', 'i', 'p', 'r'):
|
|
371 printf("Audio: SiproLab's ACELP.net\n");
|
3788
|
372 sh->format = 0x130;
|
3795
|
373 break;
|
|
374 case MKTAG('c', 'o', 'o', 'k'):
|
|
375 printf("Audio: Real's GeneralCooker (unsupported)\n");
|
|
376 tmp = 0;
|
|
377 break;
|
|
378 default:
|
|
379 printf("Audio: Unknown (%s)\n", buf);
|
|
380 tmp = 0;
|
|
381 sh->format = MKTAG(buf[0], buf[1], buf[2], buf[3]);
|
3777
|
382 }
|
|
383
|
3795
|
384 if (tmp)
|
3777
|
385 {
|
3795
|
386 /* Emulate WAVEFORMATEX struct: */
|
|
387 sh->wf = malloc(sizeof(WAVEFORMATEX));
|
|
388 memset(sh->wf, 0, sizeof(WAVEFORMATEX));
|
|
389 sh->wf->wFormatTag = sh->format;
|
|
390 sh->wf->nChannels = sh->channels;
|
|
391 sh->wf->wBitsPerSample = 16;
|
|
392 sh->wf->nSamplesPerSec = sh->samplerate;
|
|
393 sh->wf->nAvgBytesPerSec = bitrate;
|
|
394 sh->wf->nBlockAlign = frame_size; /* 19 for acelp, pff */
|
|
395 sh->wf->cbSize = 0;
|
3788
|
396
|
3795
|
397 /* insert as stream */
|
|
398 demuxer->audio->sh = sh;
|
|
399 sh->ds = demuxer->audio;
|
|
400 demuxer->audio->id = stream_id;
|
3788
|
401
|
3795
|
402 if (priv->last_a_stream+1 < MAX_STREAMS)
|
|
403 {
|
|
404 priv->a_streams[priv->last_a_stream] = stream_id;
|
|
405 priv->last_a_stream++;
|
|
406 }
|
3777
|
407 }
|
|
408 }
|
|
409 else
|
|
410 {
|
|
411 /* video header */
|
|
412 sh_video_t *sh = new_sh_video(demuxer, stream_id);
|
|
413
|
3795
|
414 tmp = stream_read_dword_le(demuxer->stream);
|
|
415 printf("video: %.4s (%x)\n", (char *)&tmp, tmp);
|
|
416 if (tmp != MKTAG('V', 'I', 'D', 'O'))
|
3777
|
417 {
|
|
418 mp_msg(MSGT_DEMUX, MSGL_ERR, "Unsupported video codec\n");
|
|
419 goto skip_this_chunk;
|
|
420 }
|
|
421
|
|
422 sh->format = stream_read_dword_le(demuxer->stream); /* fourcc */
|
|
423 printf("video fourcc: %.4s (%x)\n", (char *)&sh->format, sh->format);
|
|
424
|
3795
|
425 /* emulate BITMAPINFOHEADER */
|
3777
|
426 sh->bih = malloc(sizeof(BITMAPINFOHEADER));
|
|
427 memset(sh->bih, 0, sizeof(BITMAPINFOHEADER));
|
|
428 sh->bih->biSize = 40;
|
|
429 sh->disp_w = sh->bih->biWidth = stream_read_word(demuxer->stream);
|
|
430 sh->disp_h = sh->bih->biHeight = stream_read_word(demuxer->stream);
|
|
431 sh->bih->biPlanes = 1;
|
|
432 sh->bih->biBitCount = 24;
|
|
433 sh->bih->biCompression = sh->format;
|
|
434 sh->bih->biSizeImage= sh->bih->biWidth*sh->bih->biHeight*3;
|
|
435
|
|
436 sh->fps = stream_read_word(demuxer->stream);
|
|
437 sh->frametime = 1.0f/sh->fps;
|
|
438
|
|
439 stream_skip(demuxer->stream, 4);
|
|
440 stream_skip(demuxer->stream, 2);
|
|
441 stream_skip(demuxer->stream, 4);
|
|
442 stream_skip(demuxer->stream, 2);
|
|
443
|
|
444 /* h263 hack */
|
3795
|
445 tmp = stream_read_dword(demuxer->stream);
|
|
446 switch (tmp)
|
3777
|
447 {
|
|
448 case 0x10000000:
|
|
449 /* sub id: 0 */
|
|
450 /* codec id: rv10 */
|
|
451 break;
|
|
452 case 0x10003000:
|
|
453 case 0x10003001:
|
|
454 /* sub id: 3 */
|
|
455 /* codec id: rv10 */
|
|
456 break;
|
|
457 case 0x20001000:
|
3788
|
458 case 0x20100001:
|
3777
|
459 /* codec id: rv20 */
|
|
460 break;
|
|
461 default:
|
|
462 /* codec id: none */
|
3795
|
463 printf("unknown id: %x\n", tmp);
|
3777
|
464 }
|
|
465
|
|
466 /* insert as stream */
|
|
467 demuxer->video->sh = sh;
|
|
468 sh->ds = demuxer->video;
|
|
469 demuxer->video->id = stream_id;
|
|
470 if (priv->last_v_stream+1 < MAX_STREAMS)
|
|
471 {
|
|
472 priv->v_streams[priv->last_v_stream] = stream_id;
|
|
473 priv->last_v_stream++;
|
|
474 }
|
|
475 }
|
|
476
|
|
477 skip_this_chunk:
|
|
478 /* skip codec info */
|
3795
|
479 tmp = stream_tell(demuxer->stream) - codec_pos;
|
|
480 stream_skip(demuxer->stream, codec_data_size - tmp);
|
3777
|
481 break;
|
|
482 }
|
|
483 case MKTAG('D', 'A', 'T', 'A'):
|
|
484 goto header_end;
|
3795
|
485 case MKTAG('I', 'N', 'D', 'X'):
|
3777
|
486 default:
|
|
487 printf("Unknown chunk: %x\n", chunk);
|
|
488 stream_skip(demuxer->stream, chunk_size - 10);
|
|
489 break;
|
|
490 }
|
|
491 }
|
|
492
|
|
493 header_end:
|
|
494 priv->num_of_packets = stream_read_dword(demuxer->stream);
|
|
495 // stream_skip(demuxer->stream, 4); /* number of packets */
|
|
496 stream_skip(demuxer->stream, 4); /* next data header */
|
|
497
|
|
498 printf("Packets in file: %d\n", priv->num_of_packets);
|
|
499
|
|
500 /* disable seeking */
|
|
501 demuxer->seekable = 0;
|
|
502
|
|
503 fail:
|
|
504 return;
|
|
505 }
|
|
506
|
|
507 void demux_close_real(demuxer_t *demuxer)
|
|
508 {
|
|
509 real_priv_t* priv = demuxer->priv;
|
|
510
|
|
511 if (priv)
|
|
512 free(priv);
|
|
513
|
|
514 return;
|
|
515 }
|