Mercurial > mplayer.hg
annotate libmpdemux/pnm.c @ 14457:65544ac80ce5
sync
author | paszczi |
---|---|
date | Mon, 10 Jan 2005 22:25:39 +0000 |
parents | 5901a6392db3 |
children | 1a02a23202c2 |
rev | line source |
---|---|
8570 | 1 /* |
2 * Copyright (C) 2000-2002 the xine project | |
3 * | |
4 * This file is part of xine, a free video player. | |
5 * | |
6 * xine is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * xine is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | |
19 * | |
20 * $Id$ | |
21 * | |
22 * pnm protocol implementation | |
23 * based upon code from joschka | |
24 */ | |
25 | |
26 #include <unistd.h> | |
27 #include <stdio.h> | |
28 #include <assert.h> | |
29 #include <string.h> | |
30 #include <sys/stat.h> | |
31 #include <fcntl.h> | |
32 #include <errno.h> | |
33 #include <stdlib.h> | |
34 #include <sys/time.h> | |
8584 | 35 #include <inttypes.h> |
8570 | 36 |
10281 | 37 #include "config.h" |
38 #ifndef HAVE_WINSOCK2 | |
39 #define closesocket close | |
40 #include <sys/socket.h> | |
41 //#include <netinet/in.h> | |
42 //#include <netdb.h> | |
43 #else | |
44 #include <winsock2.h> | |
45 #endif | |
46 | |
8570 | 47 #include "pnm.h" |
48 //#include "libreal/rmff.h" | |
49 | |
50 #define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \ | |
51 (((long)(unsigned char)(ch3) ) | \ | |
52 ( (long)(unsigned char)(ch2) << 8 ) | \ | |
53 ( (long)(unsigned char)(ch1) << 16 ) | \ | |
54 ( (long)(unsigned char)(ch0) << 24 ) ) | |
55 | |
56 | |
57 #define RMF_TAG FOURCC_TAG('.', 'R', 'M', 'F') | |
58 #define PROP_TAG FOURCC_TAG('P', 'R', 'O', 'P') | |
59 #define MDPR_TAG FOURCC_TAG('M', 'D', 'P', 'R') | |
60 #define CONT_TAG FOURCC_TAG('C', 'O', 'N', 'T') | |
61 #define DATA_TAG FOURCC_TAG('D', 'A', 'T', 'A') | |
62 #define INDX_TAG FOURCC_TAG('I', 'N', 'D', 'X') | |
63 #define PNA_TAG FOURCC_TAG('P', 'N', 'A', 0 ) | |
64 | |
65 /* | |
66 #define LOG | |
67 */ | |
68 | |
8880 | 69 #define BUF_SIZE 4096 |
70 #define HEADER_SIZE 4096 | |
8570 | 71 |
72 struct pnm_s { | |
73 | |
74 int s; | |
75 | |
76 // char *host; | |
77 // int port; | |
78 char *path; | |
79 // char *url; | |
80 | |
81 char buffer[BUF_SIZE]; /* scratch buffer */ | |
82 | |
83 /* receive buffer */ | |
84 uint8_t recv[BUF_SIZE]; | |
85 int recv_size; | |
86 int recv_read; | |
87 | |
88 uint8_t header[HEADER_SIZE]; | |
89 int header_len; | |
90 int header_read; | |
91 unsigned int seq_num[4]; /* two streams with two indices */ | |
92 unsigned int seq_current[2]; /* seqs of last stream chunk read */ | |
93 uint32_t ts_current; /* timestamp of current chunk */ | |
94 uint32_t ts_last[2]; /* timestamps of last chunks */ | |
95 unsigned int packet; /* number of last recieved packet */ | |
96 }; | |
97 | |
98 /* | |
99 * utility macros | |
100 */ | |
101 | |
102 #define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) | |
103 #define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ | |
104 (((uint8_t*)(x))[1] << 16) | \ | |
105 (((uint8_t*)(x))[2] << 8) | \ | |
106 ((uint8_t*)(x))[3]) | |
107 | |
108 /* D means direct (no pointer) */ | |
109 #define BE_16D(x) ((x & 0xff00) >> 8)|((x & 0x00ff) << 8) | |
110 | |
111 /* sizes */ | |
112 #define PREAMBLE_SIZE 8 | |
113 #define CHECKSUM_SIZE 3 | |
114 | |
115 | |
116 /* header of rm files */ | |
117 #define RM_HEADER_SIZE 0x12 | |
118 const unsigned char rm_header[]={ | |
119 0x2e, 0x52, 0x4d, 0x46, /* object_id ".RMF" */ | |
120 0x00, 0x00, 0x00, 0x12, /* header_size 0x12 */ | |
121 0x00, 0x00, /* object_version 0x00 */ | |
122 0x00, 0x00, 0x00, 0x00, /* file_version 0x00 */ | |
123 0x00, 0x00, 0x00, 0x06 /* num_headers 0x06 */ | |
124 }; | |
125 | |
126 /* data chunk header */ | |
127 #define PNM_DATA_HEADER_SIZE 18 | |
128 const unsigned char pnm_data_header[]={ | |
129 'D','A','T','A', | |
130 0,0,0,0, /* data chunk size */ | |
131 0,0, /* object version */ | |
132 0,0,0,0, /* num packets */ | |
133 0,0,0,0}; /* next data header */ | |
134 | |
135 /* pnm request chunk ids */ | |
136 | |
137 #define PNA_CLIENT_CAPS 0x03 | |
138 #define PNA_CLIENT_CHALLANGE 0x04 | |
139 #define PNA_BANDWIDTH 0x05 | |
140 #define PNA_GUID 0x13 | |
141 #define PNA_TIMESTAMP 0x17 | |
142 #define PNA_TWENTYFOUR 0x18 | |
143 | |
144 #define PNA_CLIENT_STRING 0x63 | |
145 #define PNA_PATH_REQUEST 0x52 | |
146 | |
147 const unsigned char pnm_challenge[] = "0990f6b4508b51e801bd6da011ad7b56"; | |
148 const unsigned char pnm_timestamp[] = "[15/06/1999:22:22:49 00:00]"; | |
149 const unsigned char pnm_guid[] = "3eac2411-83d5-11d2-f3ea-d7c3a51aa8b0"; | |
150 const unsigned char pnm_response[] = "97715a899cbe41cee00dd434851535bf"; | |
10350 | 151 const unsigned char client_string[] = "WinNT_9.0_6.0.6.45_plus32_MP60_en-US_686l"; |
8570 | 152 |
153 #define PNM_HEADER_SIZE 11 | |
154 const unsigned char pnm_header[] = { | |
155 'P','N','A', | |
156 0x00, 0x0a, | |
157 0x00, 0x14, | |
158 0x00, 0x02, | |
159 0x00, 0x01 }; | |
160 | |
161 #define PNM_CLIENT_CAPS_SIZE 126 | |
162 const unsigned char pnm_client_caps[] = { | |
163 0x07, 0x8a, 'p','n','r','v', | |
164 0, 0x90, 'p','n','r','v', | |
165 0, 0x64, 'd','n','e','t', | |
166 0, 0x46, 'p','n','r','v', | |
167 0, 0x32, 'd','n','e','t', | |
168 0, 0x2b, 'p','n','r','v', | |
169 0, 0x28, 'd','n','e','t', | |
170 0, 0x24, 'p','n','r','v', | |
171 0, 0x19, 'd','n','e','t', | |
172 0, 0x18, 'p','n','r','v', | |
173 0, 0x14, 's','i','p','r', | |
174 0, 0x14, 'd','n','e','t', | |
175 0, 0x24, '2','8','_','8', | |
176 0, 0x12, 'p','n','r','v', | |
177 0, 0x0f, 'd','n','e','t', | |
178 0, 0x0a, 's','i','p','r', | |
179 0, 0x0a, 'd','n','e','t', | |
180 0, 0x08, 's','i','p','r', | |
181 0, 0x06, 's','i','p','r', | |
182 0, 0x12, 'l','p','c','J', | |
183 0, 0x07, '0','5','_','6' }; | |
184 | |
185 const uint32_t pnm_default_bandwidth=10485800; | |
186 const uint32_t pnm_available_bandwidths[]={14400,19200,28800,33600,34430,57600, | |
187 115200,262200,393216,524300,1544000,10485800}; | |
188 | |
189 #define PNM_TWENTYFOUR_SIZE 16 | |
190 unsigned char pnm_twentyfour[]={ | |
191 0xd5, 0x42, 0xa3, 0x1b, 0xef, 0x1f, 0x70, 0x24, | |
192 0x85, 0x29, 0xb3, 0x8d, 0xba, 0x11, 0xf3, 0xd6 }; | |
193 | |
194 /* now other data follows. marked with 0x0000 at the beginning */ | |
195 int after_chunks_length=6; | |
196 unsigned char after_chunks[]={ | |
197 0x00, 0x00, /* mark */ | |
198 | |
199 0x50, 0x84, /* seems to be fixated */ | |
200 0x1f, 0x3a /* varies on each request (checksum ?)*/ | |
201 }; | |
202 | |
203 static void hexdump (char *buf, int length); | |
204 | |
205 static int rm_write(int s, const char *buf, int len) { | |
206 int total, timeout; | |
207 | |
208 total = 0; timeout = 30; | |
209 while (total < len){ | |
210 int n; | |
211 | |
10206
35e306346e59
Using recv/send instead read/write for proper MinGW support (it's a 4.2BSD standard). Patch by FloDt <flodt8@yahoo.de>
alex
parents:
8880
diff
changeset
|
212 n = send (s, &buf[total], len - total, 0); |
8570 | 213 |
214 if (n > 0) | |
215 total += n; | |
216 else if (n < 0) { | |
10281 | 217 #ifndef HAVE_WINSOCK2 |
8570 | 218 if ((timeout>0) && ((errno == EAGAIN) || (errno == EINPROGRESS))) { |
10281 | 219 #else |
220 if ((timeout>0) && ((errno == EAGAIN) || (WSAGetLastError() == WSAEINPROGRESS))) { | |
221 #endif | |
8570 | 222 sleep (1); timeout--; |
223 } else | |
224 return -1; | |
225 } | |
226 } | |
227 | |
228 return total; | |
229 } | |
230 | |
231 static ssize_t rm_read(int fd, void *buf, size_t count) { | |
232 | |
233 ssize_t ret, total; | |
234 | |
235 total = 0; | |
236 | |
237 while (total < count) { | |
238 | |
239 fd_set rset; | |
240 struct timeval timeout; | |
241 | |
242 FD_ZERO (&rset); | |
243 FD_SET (fd, &rset); | |
244 | |
245 timeout.tv_sec = 3; | |
246 timeout.tv_usec = 0; | |
247 | |
248 if (select (fd+1, &rset, NULL, NULL, &timeout) <= 0) { | |
249 return -1; | |
250 } | |
251 | |
10206
35e306346e59
Using recv/send instead read/write for proper MinGW support (it's a 4.2BSD standard). Patch by FloDt <flodt8@yahoo.de>
alex
parents:
8880
diff
changeset
|
252 ret=recv (fd, ((uint8_t*)buf)+total, count-total, 0); |
8570 | 253 |
254 if (ret<=0) { | |
255 printf ("input_pnm: read error.\n"); | |
256 return ret; | |
257 } else | |
258 total += ret; | |
259 } | |
260 | |
261 return total; | |
262 } | |
263 | |
264 /* | |
265 * debugging utilities | |
266 */ | |
267 | |
268 static void hexdump (char *buf, int length) { | |
269 | |
270 int i; | |
271 | |
272 printf ("input_pnm: ascii>"); | |
273 for (i = 0; i < length; i++) { | |
274 unsigned char c = buf[i]; | |
275 | |
276 if ((c >= 32) && (c <= 128)) | |
277 printf ("%c", c); | |
278 else | |
279 printf ("."); | |
280 } | |
281 printf ("\n"); | |
282 | |
283 printf ("input_pnm: hexdump> "); | |
284 for (i = 0; i < length; i++) { | |
285 unsigned char c = buf[i]; | |
286 | |
287 printf ("%02x", c); | |
288 | |
289 if ((i % 16) == 15) | |
290 printf ("\npnm: "); | |
291 | |
292 if ((i % 2) == 1) | |
293 printf (" "); | |
294 | |
295 } | |
296 printf ("\n"); | |
297 } | |
298 | |
299 /* | |
300 * pnm_get_chunk gets a chunk from stream | |
301 * and returns number of bytes read | |
302 */ | |
303 | |
304 static unsigned int pnm_get_chunk(pnm_t *p, | |
305 unsigned int max, | |
306 unsigned int *chunk_type, | |
307 char *data, int *need_response) { | |
308 | |
309 unsigned int chunk_size; | |
14164 | 310 unsigned int n; |
8570 | 311 char *ptr; |
312 | |
14164 | 313 if (max < PREAMBLE_SIZE) |
314 return -1; | |
315 | |
8570 | 316 /* get first PREAMBLE_SIZE bytes and ignore checksum */ |
317 rm_read (p->s, data, CHECKSUM_SIZE); | |
318 if (data[0] == 0x72) | |
319 rm_read (p->s, data, PREAMBLE_SIZE); | |
320 else | |
321 rm_read (p->s, data+CHECKSUM_SIZE, PREAMBLE_SIZE-CHECKSUM_SIZE); | |
322 | |
14164 | 323 max -= PREAMBLE_SIZE; |
324 | |
8570 | 325 *chunk_type = BE_32(data); |
326 chunk_size = BE_32(data+4); | |
327 | |
328 switch (*chunk_type) { | |
329 case PNA_TAG: | |
330 *need_response=0; | |
331 ptr=data+PREAMBLE_SIZE; | |
14164 | 332 if (max < 1) |
333 return -1; | |
8570 | 334 rm_read (p->s, ptr++, 1); |
14164 | 335 max -= 1; |
8570 | 336 |
337 while(1) { | |
338 /* expecting following chunk format: 0x4f <chunk size> <data...> */ | |
339 | |
14164 | 340 if (max < 2) |
341 return -1; | |
8570 | 342 rm_read (p->s, ptr, 2); |
14164 | 343 max -= 2; |
8570 | 344 if (*ptr == 'X') /* checking for server message */ |
345 { | |
346 printf("input_pnm: got a message from server:\n"); | |
14164 | 347 if (max < 1) |
348 return -1; | |
8570 | 349 rm_read (p->s, ptr+2, 1); |
14164 | 350 max = -1; |
8570 | 351 n=BE_16(ptr+1); |
14164 | 352 if (max < n) |
353 return -1; | |
8570 | 354 rm_read (p->s, ptr+3, n); |
14164 | 355 max -= n; |
8570 | 356 ptr[3+n]=0; |
357 printf("%s\n",ptr+3); | |
358 return -1; | |
359 } | |
360 | |
361 if (*ptr == 'F') /* checking for server error */ | |
362 { | |
363 printf("input_pnm: server error.\n"); | |
364 return -1; | |
365 } | |
366 if (*ptr == 'i') | |
367 { | |
368 ptr+=2; | |
369 *need_response=1; | |
370 continue; | |
371 } | |
372 if (*ptr != 0x4f) break; | |
373 n=ptr[1]; | |
14164 | 374 if (max < n) |
375 return -1; | |
8570 | 376 rm_read (p->s, ptr+2, n); |
14164 | 377 max -= n; |
8570 | 378 ptr+=(n+2); |
379 } | |
380 /* the checksum of the next chunk is ignored here */ | |
14164 | 381 if (max < 1) |
382 return -1; | |
8570 | 383 rm_read (p->s, ptr+2, 1); |
384 ptr+=3; | |
385 chunk_size=ptr-data; | |
386 break; | |
387 case RMF_TAG: | |
388 case DATA_TAG: | |
389 case PROP_TAG: | |
390 case MDPR_TAG: | |
391 case CONT_TAG: | |
14164 | 392 if (chunk_size > max || chunk_size < PREAMBLE_SIZE) { |
8570 | 393 printf("error: max chunk size exeeded (max was 0x%04x)\n", max); |
14164 | 394 #ifdef LOG |
8570 | 395 n=rm_read (p->s, &data[PREAMBLE_SIZE], 0x100 - PREAMBLE_SIZE); |
396 hexdump(data,n+PREAMBLE_SIZE); | |
14164 | 397 #endif |
8570 | 398 return -1; |
399 } | |
400 rm_read (p->s, &data[PREAMBLE_SIZE], chunk_size-PREAMBLE_SIZE); | |
401 break; | |
402 default: | |
403 *chunk_type = 0; | |
404 chunk_size = PREAMBLE_SIZE; | |
405 break; | |
406 } | |
407 | |
408 return chunk_size; | |
409 } | |
410 | |
411 /* | |
412 * writes a chunk to a buffer, returns number of bytes written | |
413 */ | |
414 | |
415 static int pnm_write_chunk(uint16_t chunk_id, uint16_t length, | |
416 const char *chunk, char *data) { | |
417 | |
418 data[0]=(chunk_id>>8)%0xff; | |
419 data[1]=chunk_id%0xff; | |
420 data[2]=(length>>8)%0xff; | |
421 data[3]=length%0xff; | |
422 memcpy(&data[4],chunk,length); | |
423 | |
424 return length+4; | |
425 } | |
426 | |
427 /* | |
428 * constructs a request and sends it | |
429 */ | |
430 | |
431 static void pnm_send_request(pnm_t *p, uint32_t bandwidth) { | |
432 | |
433 uint16_t i16; | |
434 int c=PNM_HEADER_SIZE; | |
435 char fixme[]={0,1}; | |
436 | |
437 memcpy(p->buffer,pnm_header,PNM_HEADER_SIZE); | |
438 c+=pnm_write_chunk(PNA_CLIENT_CHALLANGE,strlen(pnm_challenge), | |
439 pnm_challenge,&p->buffer[c]); | |
440 c+=pnm_write_chunk(PNA_CLIENT_CAPS,PNM_CLIENT_CAPS_SIZE, | |
441 pnm_client_caps,&p->buffer[c]); | |
442 c+=pnm_write_chunk(0x0a,0,NULL,&p->buffer[c]); | |
443 c+=pnm_write_chunk(0x0c,0,NULL,&p->buffer[c]); | |
444 c+=pnm_write_chunk(0x0d,0,NULL,&p->buffer[c]); | |
445 c+=pnm_write_chunk(0x16,2,fixme,&p->buffer[c]); | |
446 c+=pnm_write_chunk(PNA_TIMESTAMP,strlen(pnm_timestamp), | |
447 pnm_timestamp,&p->buffer[c]); | |
448 c+=pnm_write_chunk(PNA_BANDWIDTH,4, | |
449 (const char *)&pnm_default_bandwidth,&p->buffer[c]); | |
450 c+=pnm_write_chunk(0x08,0,NULL,&p->buffer[c]); | |
451 c+=pnm_write_chunk(0x0e,0,NULL,&p->buffer[c]); | |
452 c+=pnm_write_chunk(0x0f,0,NULL,&p->buffer[c]); | |
453 c+=pnm_write_chunk(0x11,0,NULL,&p->buffer[c]); | |
454 c+=pnm_write_chunk(0x10,0,NULL,&p->buffer[c]); | |
455 c+=pnm_write_chunk(0x15,0,NULL,&p->buffer[c]); | |
456 c+=pnm_write_chunk(0x12,0,NULL,&p->buffer[c]); | |
457 c+=pnm_write_chunk(PNA_GUID,strlen(pnm_guid), | |
458 pnm_guid,&p->buffer[c]); | |
459 c+=pnm_write_chunk(PNA_TWENTYFOUR,PNM_TWENTYFOUR_SIZE, | |
460 pnm_twentyfour,&p->buffer[c]); | |
461 | |
462 /* data after chunks */ | |
463 memcpy(&p->buffer[c],after_chunks,after_chunks_length); | |
464 c+=after_chunks_length; | |
465 | |
466 /* client id string */ | |
467 p->buffer[c]=PNA_CLIENT_STRING; | |
11000 | 468 i16=BE_16D((strlen(client_string)-1)); /* don't know why do we have -1 here */ |
8570 | 469 memcpy(&p->buffer[c+1],&i16,2); |
470 memcpy(&p->buffer[c+3],client_string,strlen(client_string)+1); | |
471 c=c+3+strlen(client_string)+1; | |
472 | |
473 /* file path */ | |
474 p->buffer[c]=0; | |
475 p->buffer[c+1]=PNA_PATH_REQUEST; | |
476 i16=BE_16D(strlen(p->path)); | |
477 memcpy(&p->buffer[c+2],&i16,2); | |
478 memcpy(&p->buffer[c+4],p->path,strlen(p->path)); | |
479 c=c+4+strlen(p->path); | |
480 | |
481 /* some trailing bytes */ | |
482 p->buffer[c]='y'; | |
483 p->buffer[c+1]='B'; | |
484 | |
485 rm_write(p->s,p->buffer,c+2); | |
486 } | |
487 | |
488 /* | |
489 * pnm_send_response sends a response of a challenge | |
490 */ | |
491 | |
492 static void pnm_send_response(pnm_t *p, const char *response) { | |
493 | |
494 int size=strlen(response); | |
495 | |
496 p->buffer[0]=0x23; | |
497 p->buffer[1]=0; | |
498 p->buffer[2]=(unsigned char) size; | |
499 | |
500 memcpy(&p->buffer[3], response, size); | |
501 | |
502 rm_write (p->s, p->buffer, size+3); | |
503 | |
504 } | |
505 | |
506 /* | |
507 * get headers and challenge and fix headers | |
508 * write headers to p->header | |
509 * write challenge to p->buffer | |
510 * | |
511 * return 0 on error. != 0 on success | |
512 */ | |
513 | |
514 static int pnm_get_headers(pnm_t *p, int *need_response) { | |
515 | |
516 uint32_t chunk_type; | |
517 uint8_t *ptr=p->header; | |
518 uint8_t *prop_hdr=NULL; | |
519 int chunk_size,size=0; | |
520 int nr; | |
521 /* rmff_header_t *h; */ | |
522 | |
523 *need_response=0; | |
524 | |
525 while(1) { | |
526 if (HEADER_SIZE-size<=0) | |
527 { | |
528 printf("input_pnm: header buffer overflow. exiting\n"); | |
529 return 0; | |
530 } | |
531 chunk_size=pnm_get_chunk(p,HEADER_SIZE-size,&chunk_type,ptr,&nr); | |
532 if (chunk_size < 0) return 0; | |
533 if (chunk_type == 0) break; | |
534 if (chunk_type == PNA_TAG) | |
535 { | |
536 memcpy(ptr, rm_header, RM_HEADER_SIZE); | |
537 chunk_size=RM_HEADER_SIZE; | |
538 *need_response=nr; | |
539 } | |
540 if (chunk_type == DATA_TAG) | |
541 chunk_size=0; | |
542 if (chunk_type == RMF_TAG) | |
543 chunk_size=0; | |
544 if (chunk_type == PROP_TAG) | |
545 prop_hdr=ptr; | |
546 size+=chunk_size; | |
547 ptr+=chunk_size; | |
548 } | |
549 | |
8852 | 550 if (!prop_hdr) { |
551 printf("input_pnm: error while parsing headers.\n"); | |
552 return 0; | |
553 } | |
554 | |
8570 | 555 /* set data offset */ |
556 size--; | |
557 prop_hdr[42]=(size>>24)%0xff; | |
558 prop_hdr[43]=(size>>16)%0xff; | |
559 prop_hdr[44]=(size>>8)%0xff; | |
560 prop_hdr[45]=(size)%0xff; | |
561 size++; | |
562 | |
563 /* read challenge */ | |
564 memcpy (p->buffer, ptr, PREAMBLE_SIZE); | |
565 rm_read (p->s, &p->buffer[PREAMBLE_SIZE], 64); | |
566 | |
567 /* now write a data header */ | |
568 memcpy(ptr, pnm_data_header, PNM_DATA_HEADER_SIZE); | |
569 size+=PNM_DATA_HEADER_SIZE; | |
570 /* | |
571 h=rmff_scan_header(p->header); | |
572 rmff_fix_header(h); | |
573 p->header_len=rmff_get_header_size(h); | |
574 rmff_dump_header(h, p->header, HEADER_SIZE); | |
575 */ | |
576 p->header_len=size; | |
577 | |
578 return 1; | |
579 } | |
580 | |
581 /* | |
582 * determine correct stream number by looking at indices | |
583 */ | |
584 | |
585 static int pnm_calc_stream(pnm_t *p) { | |
586 | |
587 char str0=0,str1=0; | |
588 | |
589 /* looking at the first index to | |
590 * find possible stream types | |
591 */ | |
592 if (p->seq_current[0]==p->seq_num[0]) str0=1; | |
593 if (p->seq_current[0]==p->seq_num[2]) str1=1; | |
594 | |
595 switch (str0+str1) { | |
596 case 1: /* one is possible, good. */ | |
597 if (str0) | |
598 { | |
599 p->seq_num[0]++; | |
600 p->seq_num[1]=p->seq_current[1]+1; | |
601 return 0; | |
602 } else | |
603 { | |
604 p->seq_num[2]++; | |
605 p->seq_num[3]=p->seq_current[1]+1; | |
606 return 1; | |
607 } | |
608 break; | |
609 case 0: | |
610 case 2: /* both types or none possible, not so good */ | |
611 /* try to figure out by second index */ | |
612 if ( (p->seq_current[1] == p->seq_num[1]) | |
613 &&(p->seq_current[1] != p->seq_num[3])) | |
614 { | |
615 /* ok, only stream0 matches */ | |
616 p->seq_num[0]=p->seq_current[0]+1; | |
617 p->seq_num[1]++; | |
618 return 0; | |
619 } | |
620 if ( (p->seq_current[1] == p->seq_num[3]) | |
621 &&(p->seq_current[1] != p->seq_num[1])) | |
622 { | |
623 /* ok, only stream1 matches */ | |
624 p->seq_num[2]=p->seq_current[0]+1; | |
625 p->seq_num[3]++; | |
626 return 1; | |
627 } | |
628 /* wow, both streams match, or not. */ | |
629 /* now we try to decide by timestamps */ | |
630 if (p->ts_current < p->ts_last[1]) | |
631 return 0; | |
632 if (p->ts_current < p->ts_last[0]) | |
633 return 1; | |
634 /* does not help, we guess type 0 */ | |
635 #ifdef LOG | |
636 printf("guessing stream# 0\n"); | |
637 #endif | |
638 p->seq_num[0]=p->seq_current[0]+1; | |
639 p->seq_num[1]=p->seq_current[1]+1; | |
640 return 0; | |
641 break; | |
642 } | |
643 printf("input_pnm: wow, something very nasty happened in pnm_calc_stream\n"); | |
644 return 2; | |
645 } | |
646 | |
647 /* | |
648 * gets a stream chunk and writes it to a recieve buffer | |
649 */ | |
650 | |
651 static int pnm_get_stream_chunk(pnm_t *p) { | |
652 | |
653 int n; | |
654 char keepalive='!'; | |
655 unsigned int fof1, fof2, stream; | |
656 | |
657 /* send a keepalive */ | |
658 /* realplayer seems to do that every 43th package */ | |
659 if ((p->packet%43) == 42) | |
660 { | |
661 rm_write(p->s,&keepalive,1); | |
662 } | |
663 | |
664 /* data chunks begin with: 'Z' <o> <o> <i1> 'Z' <i2> | |
665 * where <o> is the offset to next stream chunk, | |
666 * <i1> is a 16 bit index | |
667 * <i2> is a 8 bit index which counts from 0x10 to somewhere | |
668 */ | |
669 | |
670 n = rm_read (p->s, p->buffer, 8); | |
671 if (n<8) return 0; | |
672 | |
673 /* skip 8 bytes if 0x62 is read */ | |
674 if (p->buffer[0] == 0x62) | |
675 { | |
676 n = rm_read (p->s, p->buffer, 8); | |
677 if (n<8) return 0; | |
678 #ifdef LOG | |
679 printf("input_pnm: had to seek 8 bytes on 0x62\n"); | |
680 #endif | |
681 } | |
682 | |
683 /* a server message */ | |
684 if (p->buffer[0] == 'X') | |
685 { | |
686 int size=BE_16(&p->buffer[1]); | |
687 | |
688 rm_read (p->s, &p->buffer[8], size-5); | |
689 p->buffer[size+3]=0; | |
690 printf("input_pnm: got message from server while reading stream:\n%s\n", &p->buffer[3]); | |
691 return 0; | |
692 } | |
693 if (p->buffer[0] == 'F') | |
694 { | |
695 printf("input_pnm: server error.\n"); | |
696 return 0; | |
697 } | |
698 | |
699 /* skip bytewise to next chunk. | |
11000 | 700 * seems, that we don't need that, if we send enough |
8570 | 701 * keepalives |
702 */ | |
703 n=0; | |
704 while (p->buffer[0] != 0x5a) { | |
705 int i; | |
706 for (i=1; i<8; i++) { | |
707 p->buffer[i-1]=p->buffer[i]; | |
708 } | |
709 rm_read (p->s, &p->buffer[7], 1); | |
710 n++; | |
711 } | |
712 | |
713 #ifdef LOG | |
714 if (n) printf("input_pnm: had to seek %i bytes to next chunk\n", n); | |
715 #endif | |
716 | |
717 /* check for 'Z's */ | |
718 if ((p->buffer[0] != 0x5a)||(p->buffer[7] != 0x5a)) | |
719 { | |
720 printf("input_pnm: bad boundaries\n"); | |
721 hexdump(p->buffer, 8); | |
722 return 0; | |
723 } | |
724 | |
725 /* check offsets */ | |
726 fof1=BE_16(&p->buffer[1]); | |
727 fof2=BE_16(&p->buffer[3]); | |
728 if (fof1 != fof2) | |
729 { | |
730 printf("input_pnm: frame offsets are different: 0x%04x 0x%04x\n",fof1,fof2); | |
731 return 0; | |
732 } | |
733 | |
734 /* get first index */ | |
735 p->seq_current[0]=BE_16(&p->buffer[5]); | |
736 | |
737 /* now read the rest of stream chunk */ | |
738 n = rm_read (p->s, &p->recv[5], fof1-5); | |
739 if (n<(fof1-5)) return 0; | |
740 | |
741 /* get second index */ | |
742 p->seq_current[1]=p->recv[5]; | |
743 | |
744 /* get timestamp */ | |
745 p->ts_current=BE_32(&p->recv[6]); | |
746 | |
747 /* get stream number */ | |
748 stream=pnm_calc_stream(p); | |
749 | |
750 /* saving timestamp */ | |
751 p->ts_last[stream]=p->ts_current; | |
752 | |
753 /* constructing a data packet header */ | |
754 | |
755 p->recv[0]=0; /* object version */ | |
756 p->recv[1]=0; | |
757 | |
758 fof2=BE_16(&fof2); | |
759 memcpy(&p->recv[2], &fof2, 2); | |
760 /*p->recv[2]=(fof2>>8)%0xff;*/ /* length */ | |
761 /*p->recv[3]=(fof2)%0xff;*/ | |
762 | |
763 p->recv[4]=0; /* stream number */ | |
764 p->recv[5]=stream; | |
765 | |
766 p->recv[10]=p->recv[10] & 0xfe; /* streambox seems to do that... */ | |
767 | |
768 p->packet++; | |
769 | |
770 p->recv_size=fof1; | |
771 | |
772 return fof1; | |
773 } | |
774 | |
775 // pnm_t *pnm_connect(const char *mrl) { | |
776 pnm_t *pnm_connect(int fd, char *path) { | |
777 | |
778 pnm_t *p=malloc(sizeof(pnm_t)); | |
8852 | 779 int need_response=0; |
8570 | 780 |
781 p->path=strdup(path); | |
782 p->s=fd; | |
783 | |
784 pnm_send_request(p,pnm_available_bandwidths[10]); | |
785 if (!pnm_get_headers(p, &need_response)) { | |
786 printf ("input_pnm: failed to set up stream\n"); | |
787 free(p->path); | |
788 free(p); | |
789 return NULL; | |
790 } | |
791 if (need_response) | |
792 pnm_send_response(p, pnm_response); | |
793 p->ts_last[0]=0; | |
794 p->ts_last[1]=0; | |
795 | |
796 /* copy header to recv */ | |
797 | |
798 memcpy(p->recv, p->header, p->header_len); | |
799 p->recv_size = p->header_len; | |
800 p->recv_read = 0; | |
801 | |
802 return p; | |
803 } | |
804 | |
805 int pnm_read (pnm_t *this, char *data, int len) { | |
806 | |
807 int to_copy=len; | |
808 char *dest=data; | |
809 char *source=this->recv + this->recv_read; | |
810 int fill=this->recv_size - this->recv_read; | |
811 | |
812 if (len < 0) return 0; | |
813 while (to_copy > fill) { | |
814 | |
815 memcpy(dest, source, fill); | |
816 to_copy -= fill; | |
817 dest += fill; | |
818 this->recv_read=0; | |
819 | |
820 if (!pnm_get_stream_chunk (this)) { | |
821 #ifdef LOG | |
822 printf ("input_pnm: %d of %d bytes provided\n", len-to_copy, len); | |
823 #endif | |
824 return len-to_copy; | |
825 } | |
826 source = this->recv; | |
827 fill = this->recv_size - this->recv_read; | |
828 } | |
829 | |
830 memcpy(dest, source, to_copy); | |
831 this->recv_read += to_copy; | |
832 | |
833 #ifdef LOG | |
834 printf ("input_pnm: %d bytes provided\n", len); | |
835 #endif | |
836 | |
837 return len; | |
838 } | |
839 | |
840 int pnm_peek_header (pnm_t *this, char *data) { | |
841 | |
842 memcpy (data, this->header, this->header_len); | |
843 return this->header_len; | |
844 } | |
845 | |
846 void pnm_close(pnm_t *p) { | |
847 | |
10281 | 848 if (p->s >= 0) closesocket(p->s); |
8570 | 849 free(p->path); |
850 free(p); | |
851 } | |
852 |