]> git.sesse.net Git - vlc/blob - modules/access/rtsp/real.c
Merge branch 'master' into lpcm_encoder
[vlc] / modules / access / rtsp / real.c
1 /*****************************************************************************
2  * real.c: real rtsp input
3  *****************************************************************************
4  * Copyright (C) 2002-2004 the xine project
5  * Copyright (C) 2005 VideoLAN
6  * $Id$
7  *
8  * Authors: Gildas Bazin <gbazin@videolan.org>
9  *          Adapted from xine which itself adapted it from joschkas real tools.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <vlc_common.h>
31 #include <vlc_memory.h>
32
33 #include "rtsp.h"
34 #include "real.h"
35 #include "real_sdpplin.h"
36
37 #define XOR_TABLE_LEN 37
38 static const unsigned char xor_table[] = {
39     0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
40     0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
41     0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
42     0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
43     0x10, 0x57, 0x05, 0x18, 0x54, 0x00, 0x00, 0x00 };
44
45 #define BE_32(x) GetDWBE(x)
46 #define LE_32(x) GetDWLE(x)
47 #define BE_16(x) GetWBE(x)
48 #define LE_16(x) GetWLE(x)
49 #define BE_32C(x,y) do {uint32_t in=y; *(uint32_t *)(x)=GetDWBE(&in);} while(0)
50 #define LE_32C(x,y) do {uint32_t in=y; *(uint32_t *)(x)=GetDWLE(&in);} while(0)
51 #define MAX(x,y) ((x>y) ? x : y)
52
53 static void hash(char *field, char *param)
54 {
55   uint32_t a, b, c, d;
56
57   /* fill variables */
58   a = LE_32(field);
59   b = LE_32(field+4);
60   c = LE_32(field+8);
61   d = LE_32(field+12);
62
63   lprintf("hash input: %x %x %x %x\n", a, b, c, d);
64   lprintf("hash parameter:\n");
65
66   a = ((b & c) | (~b & d)) + LE_32((param+0x00)) + a - 0x28955B88;
67   a = ((a << 0x07) | (a >> 0x19)) + b;
68   d = ((a & b) | (~a & c)) + LE_32((param+0x04)) + d - 0x173848AA;
69   d = ((d << 0x0c) | (d >> 0x14)) + a;
70   c = ((d & a) | (~d & b)) + LE_32((param+0x08)) + c + 0x242070DB;
71   c = ((c << 0x11) | (c >> 0x0f)) + d;
72   b = ((c & d) | (~c & a)) + LE_32((param+0x0c)) + b - 0x3E423112;
73   b = ((b << 0x16) | (b >> 0x0a)) + c;
74   a = ((b & c) | (~b & d)) + LE_32((param+0x10)) + a - 0x0A83F051;
75   a = ((a << 0x07) | (a >> 0x19)) + b;
76   d = ((a & b) | (~a & c)) + LE_32((param+0x14)) + d + 0x4787C62A;
77   d = ((d << 0x0c) | (d >> 0x14)) + a;
78   c = ((d & a) | (~d & b)) + LE_32((param+0x18)) + c - 0x57CFB9ED;
79   c = ((c << 0x11) | (c >> 0x0f)) + d;
80   b = ((c & d) | (~c & a)) + LE_32((param+0x1c)) + b - 0x02B96AFF;
81   b = ((b << 0x16) | (b >> 0x0a)) + c;
82   a = ((b & c) | (~b & d)) + LE_32((param+0x20)) + a + 0x698098D8;
83   a = ((a << 0x07) | (a >> 0x19)) + b;
84   d = ((a & b) | (~a & c)) + LE_32((param+0x24)) + d - 0x74BB0851;
85   d = ((d << 0x0c) | (d >> 0x14)) + a;
86   c = ((d & a) | (~d & b)) + LE_32((param+0x28)) + c - 0x0000A44F;
87   c = ((c << 0x11) | (c >> 0x0f)) + d;
88   b = ((c & d) | (~c & a)) + LE_32((param+0x2C)) + b - 0x76A32842;
89   b = ((b << 0x16) | (b >> 0x0a)) + c;
90   a = ((b & c) | (~b & d)) + LE_32((param+0x30)) + a + 0x6B901122;
91   a = ((a << 0x07) | (a >> 0x19)) + b;
92   d = ((a & b) | (~a & c)) + LE_32((param+0x34)) + d - 0x02678E6D;
93   d = ((d << 0x0c) | (d >> 0x14)) + a;
94   c = ((d & a) | (~d & b)) + LE_32((param+0x38)) + c - 0x5986BC72;
95   c = ((c << 0x11) | (c >> 0x0f)) + d;
96   b = ((c & d) | (~c & a)) + LE_32((param+0x3c)) + b + 0x49B40821;
97   b = ((b << 0x16) | (b >> 0x0a)) + c;
98
99   a = ((b & d) | (~d & c)) + LE_32((param+0x04)) + a - 0x09E1DA9E;
100   a = ((a << 0x05) | (a >> 0x1b)) + b;
101   d = ((a & c) | (~c & b)) + LE_32((param+0x18)) + d - 0x3FBF4CC0;
102   d = ((d << 0x09) | (d >> 0x17)) + a;
103   c = ((d & b) | (~b & a)) + LE_32((param+0x2c)) + c + 0x265E5A51;
104   c = ((c << 0x0e) | (c >> 0x12)) + d;
105   b = ((c & a) | (~a & d)) + LE_32((param+0x00)) + b - 0x16493856;
106   b = ((b << 0x14) | (b >> 0x0c)) + c;
107   a = ((b & d) | (~d & c)) + LE_32((param+0x14)) + a - 0x29D0EFA3;
108   a = ((a << 0x05) | (a >> 0x1b)) + b;
109   d = ((a & c) | (~c & b)) + LE_32((param+0x28)) + d + 0x02441453;
110   d = ((d << 0x09) | (d >> 0x17)) + a;
111   c = ((d & b) | (~b & a)) + LE_32((param+0x3c)) + c - 0x275E197F;
112   c = ((c << 0x0e) | (c >> 0x12)) + d;
113   b = ((c & a) | (~a & d)) + LE_32((param+0x10)) + b - 0x182C0438;
114   b = ((b << 0x14) | (b >> 0x0c)) + c;
115   a = ((b & d) | (~d & c)) + LE_32((param+0x24)) + a + 0x21E1CDE6;
116   a = ((a << 0x05) | (a >> 0x1b)) + b;
117   d = ((a & c) | (~c & b)) + LE_32((param+0x38)) + d - 0x3CC8F82A;
118   d = ((d << 0x09) | (d >> 0x17)) + a;
119   c = ((d & b) | (~b & a)) + LE_32((param+0x0c)) + c - 0x0B2AF279;
120   c = ((c << 0x0e) | (c >> 0x12)) + d;
121   b = ((c & a) | (~a & d)) + LE_32((param+0x20)) + b + 0x455A14ED;
122   b = ((b << 0x14) | (b >> 0x0c)) + c;
123   a = ((b & d) | (~d & c)) + LE_32((param+0x34)) + a - 0x561C16FB;
124   a = ((a << 0x05) | (a >> 0x1b)) + b;
125   d = ((a & c) | (~c & b)) + LE_32((param+0x08)) + d - 0x03105C08;
126   d = ((d << 0x09) | (d >> 0x17)) + a;
127   c = ((d & b) | (~b & a)) + LE_32((param+0x1c)) + c + 0x676F02D9;
128   c = ((c << 0x0e) | (c >> 0x12)) + d;
129   b = ((c & a) | (~a & d)) + LE_32((param+0x30)) + b - 0x72D5B376;
130   b = ((b << 0x14) | (b >> 0x0c)) + c;
131
132   a = (b ^ c ^ d) + LE_32((param+0x14)) + a - 0x0005C6BE;
133   a = ((a << 0x04) | (a >> 0x1c)) + b;
134   d = (a ^ b ^ c) + LE_32((param+0x20)) + d - 0x788E097F;
135   d = ((d << 0x0b) | (d >> 0x15)) + a;
136   c = (d ^ a ^ b) + LE_32((param+0x2c)) + c + 0x6D9D6122;
137   c = ((c << 0x10) | (c >> 0x10)) + d;
138   b = (c ^ d ^ a) + LE_32((param+0x38)) + b - 0x021AC7F4;
139   b = ((b << 0x17) | (b >> 0x09)) + c;
140   a = (b ^ c ^ d) + LE_32((param+0x04)) + a - 0x5B4115BC;
141   a = ((a << 0x04) | (a >> 0x1c)) + b;
142   d = (a ^ b ^ c) + LE_32((param+0x10)) + d + 0x4BDECFA9;
143   d = ((d << 0x0b) | (d >> 0x15)) + a;
144   c = (d ^ a ^ b) + LE_32((param+0x1c)) + c - 0x0944B4A0;
145   c = ((c << 0x10) | (c >> 0x10)) + d;
146   b = (c ^ d ^ a) + LE_32((param+0x28)) + b - 0x41404390;
147   b = ((b << 0x17) | (b >> 0x09)) + c;
148   a = (b ^ c ^ d) + LE_32((param+0x34)) + a + 0x289B7EC6;
149   a = ((a << 0x04) | (a >> 0x1c)) + b;
150   d = (a ^ b ^ c) + LE_32((param+0x00)) + d - 0x155ED806;
151   d = ((d << 0x0b) | (d >> 0x15)) + a;
152   c = (d ^ a ^ b) + LE_32((param+0x0c)) + c - 0x2B10CF7B;
153   c = ((c << 0x10) | (c >> 0x10)) + d;
154   b = (c ^ d ^ a) + LE_32((param+0x18)) + b + 0x04881D05;
155   b = ((b << 0x17) | (b >> 0x09)) + c;
156   a = (b ^ c ^ d) + LE_32((param+0x24)) + a - 0x262B2FC7;
157   a = ((a << 0x04) | (a >> 0x1c)) + b;
158   d = (a ^ b ^ c) + LE_32((param+0x30)) + d - 0x1924661B;
159   d = ((d << 0x0b) | (d >> 0x15)) + a;
160   c = (d ^ a ^ b) + LE_32((param+0x3c)) + c + 0x1fa27cf8;
161   c = ((c << 0x10) | (c >> 0x10)) + d;
162   b = (c ^ d ^ a) + LE_32((param+0x08)) + b - 0x3B53A99B;
163   b = ((b << 0x17) | (b >> 0x09)) + c;
164
165   a = ((~d | b) ^ c)  + LE_32((param+0x00)) + a - 0x0BD6DDBC;
166   a = ((a << 0x06) | (a >> 0x1a)) + b;
167   d = ((~c | a) ^ b)  + LE_32((param+0x1c)) + d + 0x432AFF97;
168   d = ((d << 0x0a) | (d >> 0x16)) + a;
169   c = ((~b | d) ^ a)  + LE_32((param+0x38)) + c - 0x546BDC59;
170   c = ((c << 0x0f) | (c >> 0x11)) + d;
171   b = ((~a | c) ^ d)  + LE_32((param+0x14)) + b - 0x036C5FC7;
172   b = ((b << 0x15) | (b >> 0x0b)) + c;
173   a = ((~d | b) ^ c)  + LE_32((param+0x30)) + a + 0x655B59C3;
174   a = ((a << 0x06) | (a >> 0x1a)) + b;
175   d = ((~c | a) ^ b)  + LE_32((param+0x0C)) + d - 0x70F3336E;
176   d = ((d << 0x0a) | (d >> 0x16)) + a;
177   c = ((~b | d) ^ a)  + LE_32((param+0x28)) + c - 0x00100B83;
178   c = ((c << 0x0f) | (c >> 0x11)) + d;
179   b = ((~a | c) ^ d)  + LE_32((param+0x04)) + b - 0x7A7BA22F;
180   b = ((b << 0x15) | (b >> 0x0b)) + c;
181   a = ((~d | b) ^ c)  + LE_32((param+0x20)) + a + 0x6FA87E4F;
182   a = ((a << 0x06) | (a >> 0x1a)) + b;
183   d = ((~c | a) ^ b)  + LE_32((param+0x3c)) + d - 0x01D31920;
184   d = ((d << 0x0a) | (d >> 0x16)) + a;
185   c = ((~b | d) ^ a)  + LE_32((param+0x18)) + c - 0x5CFEBCEC;
186   c = ((c << 0x0f) | (c >> 0x11)) + d;
187   b = ((~a | c) ^ d)  + LE_32((param+0x34)) + b + 0x4E0811A1;
188   b = ((b << 0x15) | (b >> 0x0b)) + c;
189   a = ((~d | b) ^ c)  + LE_32((param+0x10)) + a - 0x08AC817E;
190   a = ((a << 0x06) | (a >> 0x1a)) + b;
191   d = ((~c | a) ^ b)  + LE_32((param+0x2c)) + d - 0x42C50DCB;
192   d = ((d << 0x0a) | (d >> 0x16)) + a;
193   c = ((~b | d) ^ a)  + LE_32((param+0x08)) + c + 0x2AD7D2BB;
194   c = ((c << 0x0f) | (c >> 0x11)) + d;
195   b = ((~a | c) ^ d)  + LE_32((param+0x24)) + b - 0x14792C6F;
196   b = ((b << 0x15) | (b >> 0x0b)) + c;
197
198   lprintf("hash output: %x %x %x %x\n", a, b, c, d);
199
200   a += LE_32(field);
201   b += LE_32(field+4);
202   c += LE_32(field+8);
203   d += LE_32(field+12);
204
205   LE_32C(field, a);
206   LE_32C(field+4, b);
207   LE_32C(field+8, c);
208   LE_32C(field+12, d);
209 }
210
211 static void call_hash (char *key, char *challenge, unsigned int len) {
212   uint8_t *ptr1, *ptr2;
213   uint32_t a, b, c, d, tmp;
214
215   ptr1=(uint8_t*)(key+16);
216   ptr2=(uint8_t*)(key+20);
217
218   a = LE_32(ptr1);
219   b = (a >> 3) & 0x3f;
220   a += len * 8;
221   LE_32C(ptr1, a);
222
223   if (a < (len << 3))
224   {
225     lprintf("not verified: (len << 3) > a true\n");
226     ptr2 += 4;
227   }
228
229   tmp = LE_32(ptr2) + (len >> 0x1d);
230   LE_32C(ptr2, tmp);
231   a = 64 - b;
232   c = 0;
233   if (a <= len)
234   {
235     memcpy(key+b+24, challenge, a);
236     hash(key, key+24);
237     c = a;
238     d = c + 0x3f;
239
240     while ( d < len ) {
241       lprintf("not verified:  while ( d < len )\n");
242       hash(key, challenge+d-0x3f);
243       d += 64;
244       c += 64;
245     }
246     b = 0;
247   }
248
249   memcpy(key+b+24, challenge+c, len-c);
250 }
251
252 static void calc_response (char *result, char *field) {
253   char buf1[128];
254   char buf2[128];
255   int i;
256
257   memset (buf1, 0, 64);
258   *buf1 = 128;
259
260   memcpy (buf2, field+16, 8);
261   i = ( LE_32((buf2)) >> 3 ) & 0x3f;
262
263   if (i < 56)
264   {
265     i = 56 - i;
266   } else
267   {
268     lprintf("not verified: ! (i < 56)\n");
269     i = 120 - i;
270   }
271
272   call_hash (field, buf1, i);
273   call_hash (field, buf2, 8);
274   memcpy (result, field, 16);
275 }
276
277 static void calc_response_string (char *result, char *challenge) {
278
279   char field[128] = {
280     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
281     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
282     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
284   };
285   char zres[20];
286   int  i;
287
288   /* calculate response */
289   call_hash(field, challenge, 64);
290   calc_response(zres,field);
291
292   /* convert zres to ascii string */
293   for (i=0; i<16; i++ ) {
294     char a, b;
295
296     a = (zres[i] >> 4) & 15;
297     b = zres[i] & 15;
298
299     result[i*2]   = ((a<10) ? (a+48) : (a+87)) & 255;
300     result[i*2+1] = ((b<10) ? (b+48) : (b+87)) & 255;
301   }
302 }
303
304 static void real_calc_response_and_checksum (char *response, char *chksum, char *challenge) {
305
306   int   ch_len, resp_len;
307   int   i;
308   char *ptr;
309   char  buf[128];
310
311   /* initialize return values */
312   memset(response, 0, 64);
313   memset(chksum, 0, 34);
314
315   /* initialize buffer */
316   memset(buf, 0, 128);
317   ptr=buf;
318   BE_32C(ptr, 0xa1e9149d);
319   ptr+=4;
320   BE_32C(ptr, 0x0e6b3b59);
321   ptr+=4;
322
323   /* some (length) checks */
324   if (challenge != NULL)
325   {
326     ch_len = strlen (challenge);
327
328     if (ch_len == 40) /* what a hack... */
329     {
330       challenge[32]=0;
331       ch_len=32;
332     }
333     if ( ch_len > 56 ) ch_len=56;
334
335     /* copy challenge to buf */
336     memcpy(ptr, challenge, ch_len);
337   }
338
339   /* xor challenge bytewise with xor_table */
340   for (i=0; i<XOR_TABLE_LEN; i++)
341     ptr[i] = ptr[i] ^ xor_table[i];
342
343   calc_response_string (response, buf);
344
345   /* add tail */
346   resp_len = strlen (response);
347   strcpy (&response[resp_len], "01d0a8e3");
348
349   /* calculate checksum */
350   for (i=0; i<resp_len/4; i++)
351     chksum[i] = response[i*4];
352 }
353
354
355 /*
356  * takes a MLTI-Chunk and a rule number got from match_asm_rule,
357  * returns a pointer to selected data and number of bytes in that.
358  */
359 static int select_mlti_data(const char *mlti_chunk, int mlti_size, int selection, char **out) {
360
361   int numrules, codec, size;
362   int i;
363
364   /* MLTI chunk should begin with MLTI */
365   if ((mlti_chunk[0] != 'M')
366       ||(mlti_chunk[1] != 'L')
367       ||(mlti_chunk[2] != 'T')
368       ||(mlti_chunk[3] != 'I'))
369   {
370     lprintf("MLTI tag not detected, copying data\n");
371     memcpy(*out, mlti_chunk, mlti_size);
372     return mlti_size;
373   }
374
375   mlti_chunk+=4;
376
377   /* next 16 bits are the number of rules */
378   numrules=BE_16(mlti_chunk);
379   if (selection >= numrules) return 0;
380
381   /* now <numrules> indices of codecs follows */
382   /* we skip to selection                     */
383   mlti_chunk+=(selection+1)*2;
384
385   /* get our index */
386   codec=BE_16(mlti_chunk);
387
388   /* skip to number of codecs */
389   mlti_chunk+=(numrules-selection)*2;
390
391   /* get number of codecs */
392   numrules=BE_16(mlti_chunk);
393
394   if (codec >= numrules) {
395     lprintf("codec index >= number of codecs. %i %i\n", codec, numrules);
396     return 0;
397   }
398
399   mlti_chunk+=2;
400
401   /* now seek to selected codec */
402   for (i=0; i<codec; i++) {
403     size=BE_32(mlti_chunk);
404     mlti_chunk+=size+4;
405   }
406   size=BE_32(mlti_chunk);
407
408   memcpy(*out, mlti_chunk+4, size);
409   return size;
410 }
411
412 /*
413  * looking at stream description.
414  */
415
416 static rmff_header_t *real_parse_sdp(char *data, char **stream_rules, uint32_t bandwidth) {
417
418   sdpplin_t *desc = NULL;
419   rmff_header_t *header = NULL;
420   char *buf = NULL;
421   int len, i;
422   int max_bit_rate=0;
423   int avg_bit_rate=0;
424   int max_packet_size=0;
425   int avg_packet_size=0;
426   int duration=0;
427
428   if( !data ) return NULL;
429
430   desc=sdpplin_parse(data);
431   if( !desc ) return NULL;
432
433   buf= (char *)malloc(2048);
434   if( !buf ) goto error;
435
436   header = calloc( 1, sizeof(rmff_header_t) );
437   if( !header ) goto error;
438
439   header->fileheader=rmff_new_fileheader(4+desc->stream_count);
440   header->cont=rmff_new_cont(
441       desc->title,
442       desc->author,
443       desc->copyright,
444       desc->abstract);
445
446   header->data=rmff_new_dataheader(0,0);
447   if( !header->data ) goto error;
448
449   header->streams = calloc( desc->stream_count+1, sizeof(rmff_mdpr_t*) );
450   if( !header->streams ) goto error;
451
452   lprintf("number of streams: %u\n", desc->stream_count);
453
454   for (i=0; i<desc->stream_count; i++) {
455
456     int j=0;
457     int n;
458     char b[64];
459     int rulematches[16];
460
461     lprintf("calling asmrp_match with:\n%s\n%u\n", desc->stream[i]->asm_rule_book, bandwidth);
462
463     n=asmrp_match(desc->stream[i]->asm_rule_book, bandwidth, rulematches, sizeof(rulematches)/sizeof(rulematches[0]));
464     for (j=0; j<n; j++) {
465       lprintf("asmrp rule match: %u for stream %u\n", rulematches[j], desc->stream[i]->stream_id);
466       sprintf(b,"stream=%u;rule=%u,", desc->stream[i]->stream_id, rulematches[j]);
467       strcat(*stream_rules, b);
468     }
469
470     if (!desc->stream[i]->mlti_data) {
471       len = 0;
472       free( buf );
473       buf = NULL;
474     } else
475       len=select_mlti_data(desc->stream[i]->mlti_data,
476         desc->stream[i]->mlti_data_size, rulematches[0], &buf);
477
478     header->streams[i]=rmff_new_mdpr(
479       desc->stream[i]->stream_id,
480         desc->stream[i]->max_bit_rate,
481         desc->stream[i]->avg_bit_rate,
482         desc->stream[i]->max_packet_size,
483         desc->stream[i]->avg_packet_size,
484         desc->stream[i]->start_time,
485         desc->stream[i]->preroll,
486         desc->stream[i]->duration,
487         desc->stream[i]->stream_name,
488         desc->stream[i]->mime_type,
489         len,
490         buf);
491     if( !header->streams[i] ) goto error;
492
493     duration=MAX(duration,desc->stream[i]->duration);
494     max_bit_rate+=desc->stream[i]->max_bit_rate;
495     avg_bit_rate+=desc->stream[i]->avg_bit_rate;
496     max_packet_size=MAX(max_packet_size, desc->stream[i]->max_packet_size);
497     if (avg_packet_size)
498       avg_packet_size=(avg_packet_size + desc->stream[i]->avg_packet_size) / 2;
499     else
500       avg_packet_size=desc->stream[i]->avg_packet_size;
501   }
502
503   if (*stream_rules && strlen(*stream_rules) && (*stream_rules)[strlen(*stream_rules)-1] == ',')
504       (*stream_rules)[strlen(*stream_rules)-1]=0; /* delete last ',' in stream_rules */
505
506   header->prop=rmff_new_prop(
507       max_bit_rate,
508       avg_bit_rate,
509       max_packet_size,
510       avg_packet_size,
511       0,
512       duration,
513       0,
514       0,
515       0,
516       desc->stream_count,
517       desc->flags);
518   if( !header->prop ) goto error;
519
520   rmff_fix_header(header);
521
522   sdpplin_free( desc );
523   free( buf );
524   return header;
525
526 error:
527   sdpplin_free( desc );
528   rmff_free_header( header );
529   free( buf );
530   return NULL;
531 }
532
533 int real_get_rdt_chunk_header(rtsp_client_t *rtsp_session, rmff_pheader_t *ph) {
534
535   int n=1;
536   uint8_t header[8];
537   int size;
538   int flags1;
539   int unknown1;
540   uint32_t ts;
541
542   n=rtsp_read_data(rtsp_session, header, 8);
543   if (n<8) return 0;
544   if (header[0] != 0x24)
545   {
546     lprintf("rdt chunk not recognized: got 0x%02x\n", header[0]);
547     return 0;
548   }
549   size=(header[1]<<16)+(header[2]<<8)+(header[3]);
550   flags1=header[4];
551   if ((flags1!=0x40)&&(flags1!=0x42))
552   {
553     lprintf("got flags1: 0x%02x\n",flags1);
554     if (header[6]==0x06)
555     {
556       lprintf("got end of stream packet\n");
557       return 0;
558     }
559     header[0]=header[5];
560     header[1]=header[6];
561     header[2]=header[7];
562     n=rtsp_read_data(rtsp_session, header+3, 5);
563     if (n<5) return 0;
564     lprintf("ignoring bytes:\n");
565     n=rtsp_read_data(rtsp_session, header+4, 4);
566     if (n<4) return 0;
567     flags1=header[4];
568     size-=9;
569   }
570   unknown1=(header[5]<<16)+(header[6]<<8)+(header[7]);
571   n=rtsp_read_data(rtsp_session, header, 6);
572   if (n<6) return 0;
573   ts=BE_32(header);
574
575 #if 0
576   lprintf("ts: %u size: %u, flags: 0x%02x, unknown values: %u 0x%02x 0x%02x\n",
577           ts, size, flags1, unknown1, header[4], header[5]);
578 #endif
579
580   size+=2;
581   ph->object_version=0;
582   ph->length=size;
583   ph->stream_number=(flags1>>1)&1;
584   ph->timestamp=ts;
585   ph->reserved=0;
586   ph->flags=0;      /* TODO: determine keyframe flag and insert here? */
587   return size;
588 }
589
590 int real_get_rdt_chunk(rtsp_client_t *rtsp_session, rmff_pheader_t *ph,
591                        unsigned char **buffer) {
592
593   int n;
594   rmff_dump_pheader(ph, (char*)*buffer);
595   if (ph->length<12) return 0;
596   n=rtsp_read_data(rtsp_session, (uint8_t*)(*buffer + 12), ph->length - 12);
597   return (n <= 0) ? 0 : n+12;
598 }
599
600 //! maximum size of the rtsp description, must be < INT_MAX
601 #define MAX_DESC_BUF (20 * 1024 * 1024)
602 rmff_header_t  *real_setup_and_get_header(rtsp_client_t *rtsp_session, int bandwidth) {
603
604   char *description=NULL;
605   char *session_id=NULL;
606   rmff_header_t *h=NULL;
607   char *challenge1 = NULL;
608   char challenge2[64];
609   char checksum[34];
610   char *subscribe=NULL;
611   char *buf = malloc(256);
612   if( !buf )
613     return NULL;
614   char *mrl=rtsp_get_mrl(rtsp_session);
615   unsigned int size;
616   int status;
617
618   /* get challenge */
619   challenge1=strdup(rtsp_search_answers(rtsp_session,"RealChallenge1"));
620   lprintf("Challenge1: %s\n", challenge1);
621
622   /* request stream description */
623   rtsp_schedule_field(rtsp_session, "Accept: application/sdp");
624   sprintf(buf, "Bandwidth: %u", bandwidth);
625   rtsp_schedule_field(rtsp_session, buf);
626   rtsp_schedule_field(rtsp_session, "GUID: 00000000-0000-0000-0000-000000000000");
627   rtsp_schedule_field(rtsp_session, "RegionData: 0");
628   rtsp_schedule_field(rtsp_session, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586");
629   rtsp_schedule_field(rtsp_session, "SupportsMaximumASMBandwidth: 1");
630   rtsp_schedule_field(rtsp_session, "Language: en-US");
631   rtsp_schedule_field(rtsp_session, "Require: com.real.retain-entity-for-setup");
632
633   status=rtsp_request_describe(rtsp_session,NULL);
634   if ( status<200 || status>299 ) {
635     char *alert=rtsp_search_answers(rtsp_session,"Alert");
636     if (alert) {
637         lprintf("real: got message from server:\n%s\n", alert);
638     }
639     rtsp_send_ok( rtsp_session );
640     free( challenge1 );
641     free( alert );
642     free( buf );
643     return NULL;
644   }
645
646   /* receive description */
647   size=0;
648   if (!rtsp_search_answers(rtsp_session,"Content-length"))
649     lprintf("real: got no Content-length!\n");
650   else
651     size=atoi(rtsp_search_answers(rtsp_session,"Content-length"));
652
653   if (size > MAX_DESC_BUF) {
654     printf("real: Content-length for description too big (> %uMB)!\n",
655         MAX_DESC_BUF/(1024*1024) );
656     goto error;
657   }
658
659   if (!rtsp_search_answers(rtsp_session,"ETag"))
660     lprintf("real: got no ETag!\n");
661   else
662     session_id=strdup(rtsp_search_answers(rtsp_session,"ETag"));
663
664   lprintf("Stream description size: %i\n", size);
665
666   description = malloc(size+1);
667   if( !description )
668     goto error;
669   if( rtsp_read_data(rtsp_session, (uint8_t*)description, size) <= 0)
670     goto error;
671   description[size]=0;
672   //fprintf(stderr, "%s", description);
673
674   /* parse sdp (sdpplin) and create a header and a subscribe string */
675   subscribe = malloc(256);
676   if( !subscribe )
677     goto error;
678
679   strcpy(subscribe, "Subscribe: ");
680   h=real_parse_sdp(description, &subscribe, bandwidth);
681   if (!h)
682     goto error;
683
684   rmff_fix_header(h);
685
686 #if 0
687   fprintf("Title: %s\nCopyright: %s\nAuthor: %s\nStreams: %i\n",
688       h->cont->title, h->cont->copyright, h->cont->author, h->prop->num_streams);
689 #endif
690
691   /* setup our streams */
692   real_calc_response_and_checksum (challenge2, checksum, challenge1);
693   buf = realloc_or_free(buf, strlen(challenge2) + strlen(checksum) + 32);
694   if( !buf ) goto error;
695   sprintf(buf, "RealChallenge2: %s, sd=%s", challenge2, checksum);
696   rtsp_schedule_field(rtsp_session, buf);
697   buf = realloc_or_free(buf, strlen(session_id) + 32);
698   if( !buf ) goto error;
699   sprintf(buf, "If-Match: %s", session_id);
700   rtsp_schedule_field(rtsp_session, buf);
701   rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
702   buf = realloc_or_free(buf, strlen(mrl) + 32);
703   if( !buf ) goto error;
704   sprintf(buf, "%s/streamid=0", mrl);
705   rtsp_request_setup(rtsp_session,buf);
706
707   if (h->prop->num_streams > 1) {
708     rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
709     buf = realloc_or_free(buf, strlen(session_id) + 32);
710     if( !buf ) goto error;
711     sprintf(buf, "If-Match: %s", session_id);
712     rtsp_schedule_field(rtsp_session, buf);
713     buf = realloc_or_free(buf, strlen(mrl) + 32);
714     if( !buf ) goto error;
715     sprintf(buf, "%s/streamid=1", mrl);
716     rtsp_request_setup(rtsp_session,buf);
717   }
718   /* set stream parameter (bandwidth) with our subscribe string */
719   rtsp_schedule_field(rtsp_session, subscribe);
720   rtsp_request_setparameter(rtsp_session,NULL);
721
722   /* and finally send a play request */
723   rtsp_schedule_field(rtsp_session, "Range: npt=0-");
724   rtsp_request_play(rtsp_session,NULL);
725
726   free( challenge1 );
727   free( session_id );
728   free( description );
729   free( subscribe );
730   free( buf );
731   return h;
732
733 error:
734   rmff_free_header( h );
735   free( challenge1 );
736   free( session_id );
737   free( description );
738   free( subscribe );
739   free( buf );
740   return NULL;
741 }