Mercurial > mplayer.hg
annotate libmpdemux/pnm.c @ 10750:338d91776700
rawnv21
author | alex |
---|---|
date | Sun, 31 Aug 2003 21:39:17 +0000 |
parents | a4cba6e2dfde |
children | 6e35326c742f |
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; | |
310 int n; | |
311 char *ptr; | |
312 | |
313 /* get first PREAMBLE_SIZE bytes and ignore checksum */ | |
314 rm_read (p->s, data, CHECKSUM_SIZE); | |
315 if (data[0] == 0x72) | |
316 rm_read (p->s, data, PREAMBLE_SIZE); | |
317 else | |
318 rm_read (p->s, data+CHECKSUM_SIZE, PREAMBLE_SIZE-CHECKSUM_SIZE); | |
319 | |
320 *chunk_type = BE_32(data); | |
321 chunk_size = BE_32(data+4); | |
322 | |
323 switch (*chunk_type) { | |
324 case PNA_TAG: | |
325 *need_response=0; | |
326 ptr=data+PREAMBLE_SIZE; | |
327 rm_read (p->s, ptr++, 1); | |
328 | |
329 while(1) { | |
330 /* expecting following chunk format: 0x4f <chunk size> <data...> */ | |
331 | |
332 rm_read (p->s, ptr, 2); | |
333 if (*ptr == 'X') /* checking for server message */ | |
334 { | |
335 printf("input_pnm: got a message from server:\n"); | |
336 rm_read (p->s, ptr+2, 1); | |
337 n=BE_16(ptr+1); | |
338 rm_read (p->s, ptr+3, n); | |
339 ptr[3+n]=0; | |
340 printf("%s\n",ptr+3); | |
341 return -1; | |
342 } | |
343 | |
344 if (*ptr == 'F') /* checking for server error */ | |
345 { | |
346 printf("input_pnm: server error.\n"); | |
347 return -1; | |
348 } | |
349 if (*ptr == 'i') | |
350 { | |
351 ptr+=2; | |
352 *need_response=1; | |
353 continue; | |
354 } | |
355 if (*ptr != 0x4f) break; | |
356 n=ptr[1]; | |
357 rm_read (p->s, ptr+2, n); | |
358 ptr+=(n+2); | |
359 } | |
360 /* the checksum of the next chunk is ignored here */ | |
361 rm_read (p->s, ptr+2, 1); | |
362 ptr+=3; | |
363 chunk_size=ptr-data; | |
364 break; | |
365 case RMF_TAG: | |
366 case DATA_TAG: | |
367 case PROP_TAG: | |
368 case MDPR_TAG: | |
369 case CONT_TAG: | |
370 if (chunk_size > max) { | |
371 printf("error: max chunk size exeeded (max was 0x%04x)\n", max); | |
372 n=rm_read (p->s, &data[PREAMBLE_SIZE], 0x100 - PREAMBLE_SIZE); | |
373 hexdump(data,n+PREAMBLE_SIZE); | |
374 return -1; | |
375 } | |
376 rm_read (p->s, &data[PREAMBLE_SIZE], chunk_size-PREAMBLE_SIZE); | |
377 break; | |
378 default: | |
379 *chunk_type = 0; | |
380 chunk_size = PREAMBLE_SIZE; | |
381 break; | |
382 } | |
383 | |
384 return chunk_size; | |
385 } | |
386 | |
387 /* | |
388 * writes a chunk to a buffer, returns number of bytes written | |
389 */ | |
390 | |
391 static int pnm_write_chunk(uint16_t chunk_id, uint16_t length, | |
392 const char *chunk, char *data) { | |
393 | |
394 data[0]=(chunk_id>>8)%0xff; | |
395 data[1]=chunk_id%0xff; | |
396 data[2]=(length>>8)%0xff; | |
397 data[3]=length%0xff; | |
398 memcpy(&data[4],chunk,length); | |
399 | |
400 return length+4; | |
401 } | |
402 | |
403 /* | |
404 * constructs a request and sends it | |
405 */ | |
406 | |
407 static void pnm_send_request(pnm_t *p, uint32_t bandwidth) { | |
408 | |
409 uint16_t i16; | |
410 int c=PNM_HEADER_SIZE; | |
411 char fixme[]={0,1}; | |
412 | |
413 memcpy(p->buffer,pnm_header,PNM_HEADER_SIZE); | |
414 c+=pnm_write_chunk(PNA_CLIENT_CHALLANGE,strlen(pnm_challenge), | |
415 pnm_challenge,&p->buffer[c]); | |
416 c+=pnm_write_chunk(PNA_CLIENT_CAPS,PNM_CLIENT_CAPS_SIZE, | |
417 pnm_client_caps,&p->buffer[c]); | |
418 c+=pnm_write_chunk(0x0a,0,NULL,&p->buffer[c]); | |
419 c+=pnm_write_chunk(0x0c,0,NULL,&p->buffer[c]); | |
420 c+=pnm_write_chunk(0x0d,0,NULL,&p->buffer[c]); | |
421 c+=pnm_write_chunk(0x16,2,fixme,&p->buffer[c]); | |
422 c+=pnm_write_chunk(PNA_TIMESTAMP,strlen(pnm_timestamp), | |
423 pnm_timestamp,&p->buffer[c]); | |
424 c+=pnm_write_chunk(PNA_BANDWIDTH,4, | |
425 (const char *)&pnm_default_bandwidth,&p->buffer[c]); | |
426 c+=pnm_write_chunk(0x08,0,NULL,&p->buffer[c]); | |
427 c+=pnm_write_chunk(0x0e,0,NULL,&p->buffer[c]); | |
428 c+=pnm_write_chunk(0x0f,0,NULL,&p->buffer[c]); | |
429 c+=pnm_write_chunk(0x11,0,NULL,&p->buffer[c]); | |
430 c+=pnm_write_chunk(0x10,0,NULL,&p->buffer[c]); | |
431 c+=pnm_write_chunk(0x15,0,NULL,&p->buffer[c]); | |
432 c+=pnm_write_chunk(0x12,0,NULL,&p->buffer[c]); | |
433 c+=pnm_write_chunk(PNA_GUID,strlen(pnm_guid), | |
434 pnm_guid,&p->buffer[c]); | |
435 c+=pnm_write_chunk(PNA_TWENTYFOUR,PNM_TWENTYFOUR_SIZE, | |
436 pnm_twentyfour,&p->buffer[c]); | |
437 | |
438 /* data after chunks */ | |
439 memcpy(&p->buffer[c],after_chunks,after_chunks_length); | |
440 c+=after_chunks_length; | |
441 | |
442 /* client id string */ | |
443 p->buffer[c]=PNA_CLIENT_STRING; | |
444 i16=BE_16D((strlen(client_string)-1)); /* dont know why do we have -1 here */ | |
445 memcpy(&p->buffer[c+1],&i16,2); | |
446 memcpy(&p->buffer[c+3],client_string,strlen(client_string)+1); | |
447 c=c+3+strlen(client_string)+1; | |
448 | |
449 /* file path */ | |
450 p->buffer[c]=0; | |
451 p->buffer[c+1]=PNA_PATH_REQUEST; | |
452 i16=BE_16D(strlen(p->path)); | |
453 memcpy(&p->buffer[c+2],&i16,2); | |
454 memcpy(&p->buffer[c+4],p->path,strlen(p->path)); | |
455 c=c+4+strlen(p->path); | |
456 | |
457 /* some trailing bytes */ | |
458 p->buffer[c]='y'; | |
459 p->buffer[c+1]='B'; | |
460 | |
461 rm_write(p->s,p->buffer,c+2); | |
462 } | |
463 | |
464 /* | |
465 * pnm_send_response sends a response of a challenge | |
466 */ | |
467 | |
468 static void pnm_send_response(pnm_t *p, const char *response) { | |
469 | |
470 int size=strlen(response); | |
471 | |
472 p->buffer[0]=0x23; | |
473 p->buffer[1]=0; | |
474 p->buffer[2]=(unsigned char) size; | |
475 | |
476 memcpy(&p->buffer[3], response, size); | |
477 | |
478 rm_write (p->s, p->buffer, size+3); | |
479 | |
480 } | |
481 | |
482 /* | |
483 * get headers and challenge and fix headers | |
484 * write headers to p->header | |
485 * write challenge to p->buffer | |
486 * | |
487 * return 0 on error. != 0 on success | |
488 */ | |
489 | |
490 static int pnm_get_headers(pnm_t *p, int *need_response) { | |
491 | |
492 uint32_t chunk_type; | |
493 uint8_t *ptr=p->header; | |
494 uint8_t *prop_hdr=NULL; | |
495 int chunk_size,size=0; | |
496 int nr; | |
497 /* rmff_header_t *h; */ | |
498 | |
499 *need_response=0; | |
500 | |
501 while(1) { | |
502 if (HEADER_SIZE-size<=0) | |
503 { | |
504 printf("input_pnm: header buffer overflow. exiting\n"); | |
505 return 0; | |
506 } | |
507 chunk_size=pnm_get_chunk(p,HEADER_SIZE-size,&chunk_type,ptr,&nr); | |
508 if (chunk_size < 0) return 0; | |
509 if (chunk_type == 0) break; | |
510 if (chunk_type == PNA_TAG) | |
511 { | |
512 memcpy(ptr, rm_header, RM_HEADER_SIZE); | |
513 chunk_size=RM_HEADER_SIZE; | |
514 *need_response=nr; | |
515 } | |
516 if (chunk_type == DATA_TAG) | |
517 chunk_size=0; | |
518 if (chunk_type == RMF_TAG) | |
519 chunk_size=0; | |
520 if (chunk_type == PROP_TAG) | |
521 prop_hdr=ptr; | |
522 size+=chunk_size; | |
523 ptr+=chunk_size; | |
524 } | |
525 | |
8852 | 526 if (!prop_hdr) { |
527 printf("input_pnm: error while parsing headers.\n"); | |
528 return 0; | |
529 } | |
530 | |
8570 | 531 /* set data offset */ |
532 size--; | |
533 prop_hdr[42]=(size>>24)%0xff; | |
534 prop_hdr[43]=(size>>16)%0xff; | |
535 prop_hdr[44]=(size>>8)%0xff; | |
536 prop_hdr[45]=(size)%0xff; | |
537 size++; | |
538 | |
539 /* read challenge */ | |
540 memcpy (p->buffer, ptr, PREAMBLE_SIZE); | |
541 rm_read (p->s, &p->buffer[PREAMBLE_SIZE], 64); | |
542 | |
543 /* now write a data header */ | |
544 memcpy(ptr, pnm_data_header, PNM_DATA_HEADER_SIZE); | |
545 size+=PNM_DATA_HEADER_SIZE; | |
546 /* | |
547 h=rmff_scan_header(p->header); | |
548 rmff_fix_header(h); | |
549 p->header_len=rmff_get_header_size(h); | |
550 rmff_dump_header(h, p->header, HEADER_SIZE); | |
551 */ | |
552 p->header_len=size; | |
553 | |
554 return 1; | |
555 } | |
556 | |
557 /* | |
558 * determine correct stream number by looking at indices | |
559 */ | |
560 | |
561 static int pnm_calc_stream(pnm_t *p) { | |
562 | |
563 char str0=0,str1=0; | |
564 | |
565 /* looking at the first index to | |
566 * find possible stream types | |
567 */ | |
568 if (p->seq_current[0]==p->seq_num[0]) str0=1; | |
569 if (p->seq_current[0]==p->seq_num[2]) str1=1; | |
570 | |
571 switch (str0+str1) { | |
572 case 1: /* one is possible, good. */ | |
573 if (str0) | |
574 { | |
575 p->seq_num[0]++; | |
576 p->seq_num[1]=p->seq_current[1]+1; | |
577 return 0; | |
578 } else | |
579 { | |
580 p->seq_num[2]++; | |
581 p->seq_num[3]=p->seq_current[1]+1; | |
582 return 1; | |
583 } | |
584 break; | |
585 case 0: | |
586 case 2: /* both types or none possible, not so good */ | |
587 /* try to figure out by second index */ | |
588 if ( (p->seq_current[1] == p->seq_num[1]) | |
589 &&(p->seq_current[1] != p->seq_num[3])) | |
590 { | |
591 /* ok, only stream0 matches */ | |
592 p->seq_num[0]=p->seq_current[0]+1; | |
593 p->seq_num[1]++; | |
594 return 0; | |
595 } | |
596 if ( (p->seq_current[1] == p->seq_num[3]) | |
597 &&(p->seq_current[1] != p->seq_num[1])) | |
598 { | |
599 /* ok, only stream1 matches */ | |
600 p->seq_num[2]=p->seq_current[0]+1; | |
601 p->seq_num[3]++; | |
602 return 1; | |
603 } | |
604 /* wow, both streams match, or not. */ | |
605 /* now we try to decide by timestamps */ | |
606 if (p->ts_current < p->ts_last[1]) | |
607 return 0; | |
608 if (p->ts_current < p->ts_last[0]) | |
609 return 1; | |
610 /* does not help, we guess type 0 */ | |
611 #ifdef LOG | |
612 printf("guessing stream# 0\n"); | |
613 #endif | |
614 p->seq_num[0]=p->seq_current[0]+1; | |
615 p->seq_num[1]=p->seq_current[1]+1; | |
616 return 0; | |
617 break; | |
618 } | |
619 printf("input_pnm: wow, something very nasty happened in pnm_calc_stream\n"); | |
620 return 2; | |
621 } | |
622 | |
623 /* | |
624 * gets a stream chunk and writes it to a recieve buffer | |
625 */ | |
626 | |
627 static int pnm_get_stream_chunk(pnm_t *p) { | |
628 | |
629 int n; | |
630 char keepalive='!'; | |
631 unsigned int fof1, fof2, stream; | |
632 | |
633 /* send a keepalive */ | |
634 /* realplayer seems to do that every 43th package */ | |
635 if ((p->packet%43) == 42) | |
636 { | |
637 rm_write(p->s,&keepalive,1); | |
638 } | |
639 | |
640 /* data chunks begin with: 'Z' <o> <o> <i1> 'Z' <i2> | |
641 * where <o> is the offset to next stream chunk, | |
642 * <i1> is a 16 bit index | |
643 * <i2> is a 8 bit index which counts from 0x10 to somewhere | |
644 */ | |
645 | |
646 n = rm_read (p->s, p->buffer, 8); | |
647 if (n<8) return 0; | |
648 | |
649 /* skip 8 bytes if 0x62 is read */ | |
650 if (p->buffer[0] == 0x62) | |
651 { | |
652 n = rm_read (p->s, p->buffer, 8); | |
653 if (n<8) return 0; | |
654 #ifdef LOG | |
655 printf("input_pnm: had to seek 8 bytes on 0x62\n"); | |
656 #endif | |
657 } | |
658 | |
659 /* a server message */ | |
660 if (p->buffer[0] == 'X') | |
661 { | |
662 int size=BE_16(&p->buffer[1]); | |
663 | |
664 rm_read (p->s, &p->buffer[8], size-5); | |
665 p->buffer[size+3]=0; | |
666 printf("input_pnm: got message from server while reading stream:\n%s\n", &p->buffer[3]); | |
667 return 0; | |
668 } | |
669 if (p->buffer[0] == 'F') | |
670 { | |
671 printf("input_pnm: server error.\n"); | |
672 return 0; | |
673 } | |
674 | |
675 /* skip bytewise to next chunk. | |
676 * seems, that we dont need that, if we send enough | |
677 * keepalives | |
678 */ | |
679 n=0; | |
680 while (p->buffer[0] != 0x5a) { | |
681 int i; | |
682 for (i=1; i<8; i++) { | |
683 p->buffer[i-1]=p->buffer[i]; | |
684 } | |
685 rm_read (p->s, &p->buffer[7], 1); | |
686 n++; | |
687 } | |
688 | |
689 #ifdef LOG | |
690 if (n) printf("input_pnm: had to seek %i bytes to next chunk\n", n); | |
691 #endif | |
692 | |
693 /* check for 'Z's */ | |
694 if ((p->buffer[0] != 0x5a)||(p->buffer[7] != 0x5a)) | |
695 { | |
696 printf("input_pnm: bad boundaries\n"); | |
697 hexdump(p->buffer, 8); | |
698 return 0; | |
699 } | |
700 | |
701 /* check offsets */ | |
702 fof1=BE_16(&p->buffer[1]); | |
703 fof2=BE_16(&p->buffer[3]); | |
704 if (fof1 != fof2) | |
705 { | |
706 printf("input_pnm: frame offsets are different: 0x%04x 0x%04x\n",fof1,fof2); | |
707 return 0; | |
708 } | |
709 | |
710 /* get first index */ | |
711 p->seq_current[0]=BE_16(&p->buffer[5]); | |
712 | |
713 /* now read the rest of stream chunk */ | |
714 n = rm_read (p->s, &p->recv[5], fof1-5); | |
715 if (n<(fof1-5)) return 0; | |
716 | |
717 /* get second index */ | |
718 p->seq_current[1]=p->recv[5]; | |
719 | |
720 /* get timestamp */ | |
721 p->ts_current=BE_32(&p->recv[6]); | |
722 | |
723 /* get stream number */ | |
724 stream=pnm_calc_stream(p); | |
725 | |
726 /* saving timestamp */ | |
727 p->ts_last[stream]=p->ts_current; | |
728 | |
729 /* constructing a data packet header */ | |
730 | |
731 p->recv[0]=0; /* object version */ | |
732 p->recv[1]=0; | |
733 | |
734 fof2=BE_16(&fof2); | |
735 memcpy(&p->recv[2], &fof2, 2); | |
736 /*p->recv[2]=(fof2>>8)%0xff;*/ /* length */ | |
737 /*p->recv[3]=(fof2)%0xff;*/ | |
738 | |
739 p->recv[4]=0; /* stream number */ | |
740 p->recv[5]=stream; | |
741 | |
742 p->recv[10]=p->recv[10] & 0xfe; /* streambox seems to do that... */ | |
743 | |
744 p->packet++; | |
745 | |
746 p->recv_size=fof1; | |
747 | |
748 return fof1; | |
749 } | |
750 | |
751 // pnm_t *pnm_connect(const char *mrl) { | |
752 pnm_t *pnm_connect(int fd, char *path) { | |
753 | |
754 pnm_t *p=malloc(sizeof(pnm_t)); | |
8852 | 755 int need_response=0; |
8570 | 756 |
757 p->path=strdup(path); | |
758 p->s=fd; | |
759 | |
760 pnm_send_request(p,pnm_available_bandwidths[10]); | |
761 if (!pnm_get_headers(p, &need_response)) { | |
762 printf ("input_pnm: failed to set up stream\n"); | |
763 free(p->path); | |
764 free(p); | |
765 return NULL; | |
766 } | |
767 if (need_response) | |
768 pnm_send_response(p, pnm_response); | |
769 p->ts_last[0]=0; | |
770 p->ts_last[1]=0; | |
771 | |
772 /* copy header to recv */ | |
773 | |
774 memcpy(p->recv, p->header, p->header_len); | |
775 p->recv_size = p->header_len; | |
776 p->recv_read = 0; | |
777 | |
778 return p; | |
779 } | |
780 | |
781 int pnm_read (pnm_t *this, char *data, int len) { | |
782 | |
783 int to_copy=len; | |
784 char *dest=data; | |
785 char *source=this->recv + this->recv_read; | |
786 int fill=this->recv_size - this->recv_read; | |
787 | |
788 if (len < 0) return 0; | |
789 while (to_copy > fill) { | |
790 | |
791 memcpy(dest, source, fill); | |
792 to_copy -= fill; | |
793 dest += fill; | |
794 this->recv_read=0; | |
795 | |
796 if (!pnm_get_stream_chunk (this)) { | |
797 #ifdef LOG | |
798 printf ("input_pnm: %d of %d bytes provided\n", len-to_copy, len); | |
799 #endif | |
800 return len-to_copy; | |
801 } | |
802 source = this->recv; | |
803 fill = this->recv_size - this->recv_read; | |
804 } | |
805 | |
806 memcpy(dest, source, to_copy); | |
807 this->recv_read += to_copy; | |
808 | |
809 #ifdef LOG | |
810 printf ("input_pnm: %d bytes provided\n", len); | |
811 #endif | |
812 | |
813 return len; | |
814 } | |
815 | |
816 int pnm_peek_header (pnm_t *this, char *data) { | |
817 | |
818 memcpy (data, this->header, this->header_len); | |
819 return this->header_len; | |
820 } | |
821 | |
822 void pnm_close(pnm_t *p) { | |
823 | |
10281 | 824 if (p->s >= 0) closesocket(p->s); |
8570 | 825 free(p->path); |
826 free(p); | |
827 } | |
828 |