comparison stream/pnm.c @ 19271:64d82a45a05d

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