comparison libmpdemux/pnm.c @ 8570:16af93c01dbf

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