m_config.c: cosmetics: Move functions to avoid forward declarations
[mplayer.git] / stream / pnm.c
blob40da142b3388e6191477ff3ddb9451e3ef58a483
1 /*
2 * Copyright (C) 2000-2002 the xine project
4 * This file is part of xine, a free video player.
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * $Id$
22 * pnm protocol implementation
23 * based upon code from joschka
26 #include "config.h"
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 #if !HAVE_WINSOCK2_H
39 #include <sys/socket.h>
40 //#include <netinet/in.h>
41 //#include <netdb.h>
42 #else
43 #include <winsock2.h>
44 #endif
46 #include "ffmpeg_files/intreadwrite.h"
48 #include "stream.h"
49 #include "libmpdemux/demuxer.h"
50 #include "osdep/timer.h"
51 #include "network.h"
52 #include "pnm.h"
53 #include "tcp.h"
54 //#include "libreal/rmff.h"
56 extern int network_bandwidth;
58 #define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \
59 (((long)(unsigned char)(ch3) ) | \
60 ( (long)(unsigned char)(ch2) << 8 ) | \
61 ( (long)(unsigned char)(ch1) << 16 ) | \
62 ( (long)(unsigned char)(ch0) << 24 ) )
65 #define RMF_TAG FOURCC_TAG('.', 'R', 'M', 'F')
66 #define PROP_TAG FOURCC_TAG('P', 'R', 'O', 'P')
67 #define MDPR_TAG FOURCC_TAG('M', 'D', 'P', 'R')
68 #define CONT_TAG FOURCC_TAG('C', 'O', 'N', 'T')
69 #define DATA_TAG FOURCC_TAG('D', 'A', 'T', 'A')
70 #define INDX_TAG FOURCC_TAG('I', 'N', 'D', 'X')
71 #define PNA_TAG FOURCC_TAG('P', 'N', 'A', 0 )
74 #define LOG
77 #define BUF_SIZE 4096
78 #define HEADER_SIZE 4096
80 struct pnm_s {
82 int s;
84 // char *host;
85 // int port;
86 char *path;
87 // char *url;
89 char buffer[BUF_SIZE]; /* scratch buffer */
91 /* receive buffer */
92 uint8_t recv[BUF_SIZE];
93 int recv_size;
94 int recv_read;
96 uint8_t header[HEADER_SIZE];
97 int header_len;
98 int header_read;
99 unsigned int seq_num[4]; /* two streams with two indices */
100 unsigned int seq_current[2]; /* seqs of last stream chunk read */
101 uint32_t ts_current; /* timestamp of current chunk */
102 uint32_t ts_last[2]; /* timestamps of last chunks */
103 unsigned int packet; /* number of last recieved packet */
106 /* sizes */
107 #define PREAMBLE_SIZE 8
108 #define CHECKSUM_SIZE 3
111 /* header of rm files */
112 static const unsigned char rm_header[]={
113 0x2e, 0x52, 0x4d, 0x46, /* object_id ".RMF" */
114 0x00, 0x00, 0x00, 0x12, /* header_size 0x12 */
115 0x00, 0x00, /* object_version 0x00 */
116 0x00, 0x00, 0x00, 0x00, /* file_version 0x00 */
117 0x00, 0x00, 0x00, 0x06 /* num_headers 0x06 */
120 /* data chunk header */
121 static 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 */
128 /* pnm request chunk ids */
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
137 #define PNA_CLIENT_STRING 0x63
138 #define PNA_PATH_REQUEST 0x52
140 static const unsigned char pnm_challenge[] = "0990f6b4508b51e801bd6da011ad7b56";
141 static const unsigned char pnm_timestamp[] = "[15/06/1999:22:22:49 00:00]";
142 static const unsigned char pnm_guid[] = "3eac2411-83d5-11d2-f3ea-d7c3a51aa8b0";
143 static const unsigned char pnm_response[] = "97715a899cbe41cee00dd434851535bf";
144 static const unsigned char client_string[] = "WinNT_9.0_6.0.6.45_plus32_MP60_en-US_686l";
146 static const unsigned char pnm_header[] = {
147 'P','N','A',
148 0x00, 0x0a,
149 0x00, 0x14,
150 0x00, 0x02,
151 0x00, 0x01 };
153 static const unsigned char pnm_client_caps[] = {
154 0x07, 0x8a, 'p','n','r','v',
155 0, 0x90, 'p','n','r','v',
156 0, 0x64, 'd','n','e','t',
157 0, 0x46, 'p','n','r','v',
158 0, 0x32, 'd','n','e','t',
159 0, 0x2b, 'p','n','r','v',
160 0, 0x28, 'd','n','e','t',
161 0, 0x24, 'p','n','r','v',
162 0, 0x19, 'd','n','e','t',
163 0, 0x18, 'p','n','r','v',
164 0, 0x14, 's','i','p','r',
165 0, 0x14, 'd','n','e','t',
166 0, 0x24, '2','8','_','8',
167 0, 0x12, 'p','n','r','v',
168 0, 0x0f, 'd','n','e','t',
169 0, 0x0a, 's','i','p','r',
170 0, 0x0a, 'd','n','e','t',
171 0, 0x08, 's','i','p','r',
172 0, 0x06, 's','i','p','r',
173 0, 0x12, 'l','p','c','J',
174 0, 0x07, '0','5','_','6' };
176 static const uint32_t pnm_default_bandwidth=10485800;
177 static const uint32_t pnm_available_bandwidths[]={14400,19200,28800,33600,34430,57600,
178 115200,262200,393216,524300,1544000,10485800};
180 static const unsigned char pnm_twentyfour[]={
181 0xd5, 0x42, 0xa3, 0x1b, 0xef, 0x1f, 0x70, 0x24,
182 0x85, 0x29, 0xb3, 0x8d, 0xba, 0x11, 0xf3, 0xd6 };
184 /* now other data follows. marked with 0x0000 at the beginning */
185 static const unsigned char after_chunks[]={
186 0x00, 0x00, /* mark */
188 0x50, 0x84, /* seems to be fixated */
189 0x1f, 0x3a /* varies on each request (checksum ?)*/
192 static void hexdump (char *buf, int length);
194 static int rm_write(int s, const char *buf, int len) {
195 int total, timeout;
197 total = 0; timeout = 30;
198 while (total < len){
199 int n;
201 n = send (s, &buf[total], len - total, 0);
203 if (n > 0)
204 total += n;
205 else if (n < 0) {
206 #if !HAVE_WINSOCK2_H
207 if (timeout>0 && (errno == EAGAIN || errno == EINPROGRESS)) {
208 #else
209 if (timeout>0 && (errno == EAGAIN || WSAGetLastError() == WSAEINPROGRESS)) {
210 #endif
211 usec_sleep (1000000); timeout--;
212 } else
213 return -1;
217 return total;
220 static ssize_t rm_read(int fd, void *buf, size_t count) {
222 ssize_t ret, total;
224 total = 0;
226 while (total < count) {
228 fd_set rset;
229 struct timeval timeout;
231 FD_ZERO (&rset);
232 FD_SET (fd, &rset);
234 timeout.tv_sec = 3;
235 timeout.tv_usec = 0;
237 if (select (fd+1, &rset, NULL, NULL, &timeout) <= 0) {
238 return -1;
241 ret=recv (fd, ((uint8_t*)buf)+total, count-total, 0);
243 if (ret<=0) {
244 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: read error.\n");
245 return ret;
246 } else
247 total += ret;
250 return total;
254 * debugging utilities
257 static void hexdump (char *buf, int length) {
259 int i;
261 mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: ascii>");
262 for (i = 0; i < length; i++) {
263 unsigned char c = buf[i];
265 if (c >= 32 && c <= 128)
266 mp_msg(MSGT_OPEN, MSGL_INFO, "%c", c);
267 else
268 mp_msg(MSGT_OPEN, MSGL_INFO, ".");
270 mp_msg(MSGT_OPEN, MSGL_INFO, "\n");
272 mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: hexdump> ");
273 for (i = 0; i < length; i++) {
274 unsigned char c = buf[i];
276 mp_msg(MSGT_OPEN, MSGL_INFO, "%02x", c);
278 if ((i % 16) == 15)
279 mp_msg(MSGT_OPEN, MSGL_INFO, "\npnm: ");
281 if ((i % 2) == 1)
282 mp_msg(MSGT_OPEN, MSGL_INFO, " ");
285 mp_msg(MSGT_OPEN, MSGL_INFO, "\n");
289 * pnm_get_chunk gets a chunk from stream
290 * and returns number of bytes read
293 static int pnm_get_chunk(pnm_t *p,
294 unsigned int max,
295 unsigned int *chunk_type,
296 char *data, int *need_response) {
298 unsigned int chunk_size;
299 unsigned int n;
300 char *ptr;
302 if (max < PREAMBLE_SIZE)
303 return -1;
305 /* get first PREAMBLE_SIZE bytes and ignore checksum */
306 rm_read (p->s, data, CHECKSUM_SIZE);
307 if (data[0] == 0x72)
308 rm_read (p->s, data, PREAMBLE_SIZE);
309 else
310 rm_read (p->s, data+CHECKSUM_SIZE, PREAMBLE_SIZE-CHECKSUM_SIZE);
312 max -= PREAMBLE_SIZE;
314 *chunk_type = AV_RB32(data);
315 chunk_size = AV_RB32(data+4);
317 switch (*chunk_type) {
318 case PNA_TAG:
319 *need_response=0;
320 ptr=data+PREAMBLE_SIZE;
321 if (max < 1)
322 return -1;
323 rm_read (p->s, ptr++, 1);
324 max -= 1;
326 while(1) {
327 /* expecting following chunk format: 0x4f <chunk size> <data...> */
329 if (max < 2)
330 return -1;
331 rm_read (p->s, ptr, 2);
332 max -= 2;
333 if (*ptr == 'X') /* checking for server message */
335 mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: got a message from server:\n");
336 if (max < 1)
337 return -1;
338 rm_read (p->s, ptr+2, 1);
339 max = -1;
340 n=AV_RB16(ptr+1);
341 if (max < n)
342 return -1;
343 rm_read (p->s, ptr+3, n);
344 max -= n;
345 ptr[3+n]=0;
346 mp_msg(MSGT_OPEN, MSGL_WARN, "%s\n",ptr+3);
347 return -1;
350 if (*ptr == 'F') /* checking for server error */
352 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: server error.\n");
353 return -1;
355 if (*ptr == 'i')
357 ptr+=2;
358 *need_response=1;
359 continue;
361 if (*ptr != 0x4f) break;
362 n=ptr[1];
363 if (max < n)
364 return -1;
365 rm_read (p->s, ptr+2, n);
366 max -= n;
367 ptr+=(n+2);
369 /* the checksum of the next chunk is ignored here */
370 if (max < 1)
371 return -1;
372 rm_read (p->s, ptr+2, 1);
373 ptr+=3;
374 chunk_size=ptr-data;
375 break;
376 case RMF_TAG:
377 case DATA_TAG:
378 case PROP_TAG:
379 case MDPR_TAG:
380 case CONT_TAG:
381 if (chunk_size > max || chunk_size < PREAMBLE_SIZE) {
382 mp_msg(MSGT_OPEN, MSGL_ERR, "error: max chunk size exceeded (max was 0x%04x)\n", max);
383 #ifdef LOG
384 n=rm_read (p->s, &data[PREAMBLE_SIZE], 0x100 - PREAMBLE_SIZE);
385 hexdump(data,n+PREAMBLE_SIZE);
386 #endif
387 return -1;
389 rm_read (p->s, &data[PREAMBLE_SIZE], chunk_size-PREAMBLE_SIZE);
390 break;
391 default:
392 *chunk_type = 0;
393 chunk_size = PREAMBLE_SIZE;
394 break;
397 return chunk_size;
401 * writes a chunk to a buffer, returns number of bytes written
404 static int pnm_write_chunk(uint16_t chunk_id, uint16_t length,
405 const char *chunk, char *data) {
407 AV_WB16(&data[0], chunk_id);
408 AV_WB16(&data[2], length);
409 memcpy(&data[4],chunk,length);
411 return length+4;
415 * constructs a request and sends it
418 static void pnm_send_request(pnm_t *p, uint32_t bandwidth) {
420 uint16_t i16;
421 int c=sizeof(pnm_header);
422 char fixme[]={0,1};
424 memcpy(p->buffer,pnm_header,sizeof(pnm_header));
425 c+=pnm_write_chunk(PNA_CLIENT_CHALLANGE,strlen(pnm_challenge),
426 pnm_challenge,&p->buffer[c]);
427 c+=pnm_write_chunk(PNA_CLIENT_CAPS,sizeof(pnm_client_caps),
428 pnm_client_caps,&p->buffer[c]);
429 c+=pnm_write_chunk(0x0a,0,NULL,&p->buffer[c]);
430 c+=pnm_write_chunk(0x0c,0,NULL,&p->buffer[c]);
431 c+=pnm_write_chunk(0x0d,0,NULL,&p->buffer[c]);
432 c+=pnm_write_chunk(0x16,2,fixme,&p->buffer[c]);
433 c+=pnm_write_chunk(PNA_TIMESTAMP,strlen(pnm_timestamp),
434 pnm_timestamp,&p->buffer[c]);
435 c+=pnm_write_chunk(PNA_BANDWIDTH,4,
436 (const char *)&pnm_default_bandwidth,&p->buffer[c]);
437 c+=pnm_write_chunk(0x08,0,NULL,&p->buffer[c]);
438 c+=pnm_write_chunk(0x0e,0,NULL,&p->buffer[c]);
439 c+=pnm_write_chunk(0x0f,0,NULL,&p->buffer[c]);
440 c+=pnm_write_chunk(0x11,0,NULL,&p->buffer[c]);
441 c+=pnm_write_chunk(0x10,0,NULL,&p->buffer[c]);
442 c+=pnm_write_chunk(0x15,0,NULL,&p->buffer[c]);
443 c+=pnm_write_chunk(0x12,0,NULL,&p->buffer[c]);
444 c+=pnm_write_chunk(PNA_GUID,strlen(pnm_guid),
445 pnm_guid,&p->buffer[c]);
446 c+=pnm_write_chunk(PNA_TWENTYFOUR,sizeof(pnm_twentyfour),
447 pnm_twentyfour,&p->buffer[c]);
449 /* data after chunks */
450 memcpy(&p->buffer[c],after_chunks,sizeof(after_chunks));
451 c+=sizeof(after_chunks);
453 /* client id string */
454 p->buffer[c]=PNA_CLIENT_STRING;
455 AV_WB16(&p->buffer[c+1], strlen(client_string)-1); /* don't know why do we have -1 here */
456 memcpy(&p->buffer[c+1],&i16,2);
457 memcpy(&p->buffer[c+3],client_string,strlen(client_string)+1);
458 c=c+3+strlen(client_string)+1;
460 /* file path */
461 p->buffer[c]=0;
462 p->buffer[c+1]=PNA_PATH_REQUEST;
463 AV_WB16(&p->buffer[c+2], strlen(p->path));
464 memcpy(&p->buffer[c+4],p->path,strlen(p->path));
465 c=c+4+strlen(p->path);
467 /* some trailing bytes */
468 p->buffer[c]='y';
469 p->buffer[c+1]='B';
471 rm_write(p->s,p->buffer,c+2);
475 * pnm_send_response sends a response of a challenge
478 static void pnm_send_response(pnm_t *p, const char *response) {
480 int size=strlen(response);
482 p->buffer[0]=0x23;
483 p->buffer[1]=0;
484 p->buffer[2]=(unsigned char) size;
486 memcpy(&p->buffer[3], response, size);
488 rm_write (p->s, p->buffer, size+3);
493 * get headers and challenge and fix headers
494 * write headers to p->header
495 * write challenge to p->buffer
497 * return 0 on error. != 0 on success
500 static int pnm_get_headers(pnm_t *p, int *need_response) {
502 uint32_t chunk_type;
503 uint8_t *ptr=p->header;
504 uint8_t *prop_hdr=NULL;
505 int chunk_size,size=0;
506 int nr;
507 /* rmff_header_t *h; */
509 *need_response=0;
511 while(1) {
512 if (HEADER_SIZE-size<=0)
514 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: header buffer overflow. exiting\n");
515 return 0;
517 chunk_size=pnm_get_chunk(p,HEADER_SIZE-size,&chunk_type,ptr,&nr);
518 if (chunk_size < 0) return 0;
519 if (chunk_type == 0) break;
520 if (chunk_type == PNA_TAG)
522 memcpy(ptr, rm_header, sizeof(rm_header));
523 chunk_size=sizeof(rm_header);
524 *need_response=nr;
526 if (chunk_type == DATA_TAG)
527 chunk_size=0;
528 if (chunk_type == RMF_TAG)
529 chunk_size=0;
530 if (chunk_type == PROP_TAG)
531 prop_hdr=ptr;
532 size+=chunk_size;
533 ptr+=chunk_size;
536 if (!prop_hdr) {
537 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: error while parsing headers.\n");
538 return 0;
541 /* set data offset */
542 AV_WB32(&prop_hdr[42], size - 1);
544 /* read challenge */
545 memcpy (p->buffer, ptr, PREAMBLE_SIZE);
546 rm_read (p->s, &p->buffer[PREAMBLE_SIZE], 64);
548 /* now write a data header */
549 memcpy(ptr, pnm_data_header, sizeof(pnm_data_header));
550 size+=sizeof(pnm_data_header);
552 h=rmff_scan_header(p->header);
553 rmff_fix_header(h);
554 p->header_len=rmff_get_header_size(h);
555 rmff_dump_header(h, p->header, HEADER_SIZE);
557 p->header_len=size;
559 return 1;
563 * determine correct stream number by looking at indices
566 static int pnm_calc_stream(pnm_t *p) {
568 char str0=0,str1=0;
570 /* looking at the first index to
571 * find possible stream types
573 if (p->seq_current[0]==p->seq_num[0]) str0=1;
574 if (p->seq_current[0]==p->seq_num[2]) str1=1;
576 switch (str0+str1) {
577 case 1: /* one is possible, good. */
578 if (str0)
580 p->seq_num[0]++;
581 p->seq_num[1]=p->seq_current[1]+1;
582 return 0;
583 } else
585 p->seq_num[2]++;
586 p->seq_num[3]=p->seq_current[1]+1;
587 return 1;
589 break;
590 case 0:
591 case 2: /* both types or none possible, not so good */
592 /* try to figure out by second index */
593 if ( p->seq_current[1] == p->seq_num[1]
594 && p->seq_current[1] != p->seq_num[3])
596 /* ok, only stream0 matches */
597 p->seq_num[0]=p->seq_current[0]+1;
598 p->seq_num[1]++;
599 return 0;
601 if ( p->seq_current[1] == p->seq_num[3]
602 && p->seq_current[1] != p->seq_num[1])
604 /* ok, only stream1 matches */
605 p->seq_num[2]=p->seq_current[0]+1;
606 p->seq_num[3]++;
607 return 1;
609 /* wow, both streams match, or not. */
610 /* now we try to decide by timestamps */
611 if (p->ts_current < p->ts_last[1])
612 return 0;
613 if (p->ts_current < p->ts_last[0])
614 return 1;
615 /* does not help, we guess type 0 */
616 #ifdef LOG
617 mp_msg(MSGT_OPEN, MSGL_INFO, "guessing stream# 0\n");
618 #endif
619 p->seq_num[0]=p->seq_current[0]+1;
620 p->seq_num[1]=p->seq_current[1]+1;
621 return 0;
622 break;
624 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: wow, something very nasty happened in pnm_calc_stream\n");
625 return 2;
629 * gets a stream chunk and writes it to a recieve buffer
632 static int pnm_get_stream_chunk(pnm_t *p) {
634 int n;
635 char keepalive='!';
636 unsigned int fof1, fof2, stream;
638 /* send a keepalive */
639 /* realplayer seems to do that every 43th package */
640 if (p->packet%43 == 42)
641 rm_write(p->s,&keepalive,1);
643 /* data chunks begin with: 'Z' <o> <o> <i1> 'Z' <i2>
644 * where <o> is the offset to next stream chunk,
645 * <i1> is a 16 bit index
646 * <i2> is a 8 bit index which counts from 0x10 to somewhere
649 n = rm_read (p->s, p->buffer, 8);
650 if (n<0) return -1;
651 if (n<8) return 0;
653 /* skip 8 bytes if 0x62 is read */
654 if (p->buffer[0] == 0x62)
656 n = rm_read (p->s, p->buffer, 8);
657 if (n<8) return 0;
658 #ifdef LOG
659 mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: had to seek 8 bytes on 0x62\n");
660 #endif
663 /* a server message */
664 if (p->buffer[0] == 'X')
666 int size=AV_RB16(&p->buffer[1]);
668 rm_read (p->s, &p->buffer[8], size-5);
669 p->buffer[size+3]=0;
670 mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: got message from server while reading stream:\n%s\n", &p->buffer[3]);
671 return -1;
673 if (p->buffer[0] == 'F')
675 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: server error.\n");
676 return -1;
679 /* skip bytewise to next chunk.
680 * seems, that we don't need that, if we send enough
681 * keepalives
683 n=0;
684 while (p->buffer[0] != 0x5a) {
685 int i;
686 for (i=1; i<8; i++)
687 p->buffer[i-1]=p->buffer[i];
688 rm_read (p->s, &p->buffer[7], 1);
689 n++;
692 #ifdef LOG
693 if (n) mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: had to seek %i bytes to next chunk\n", n);
694 #endif
696 /* check for 'Z's */
697 if (p->buffer[0] != 0x5a || p->buffer[7] != 0x5a)
699 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: bad boundaries\n");
700 hexdump(p->buffer, 8);
701 return 0;
704 /* check offsets */
705 fof1=AV_RB16(&p->buffer[1]);
706 fof2=AV_RB16(&p->buffer[3]);
707 if (fof1 != fof2)
709 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: frame offsets are different: 0x%04x 0x%04x\n",fof1,fof2);
710 return 0;
713 /* get first index */
714 p->seq_current[0]=AV_RB16(&p->buffer[5]);
716 /* now read the rest of stream chunk */
717 n = rm_read (p->s, &p->recv[5], fof1-5);
718 if (n<fof1-5) return 0;
720 /* get second index */
721 p->seq_current[1]=p->recv[5];
723 /* get timestamp */
724 p->ts_current=AV_RB32(&p->recv[6]);
726 /* get stream number */
727 stream=pnm_calc_stream(p);
729 /* saving timestamp */
730 p->ts_last[stream]=p->ts_current;
732 /* constructing a data packet header */
734 p->recv[0]=0; /* object version */
735 p->recv[1]=0;
737 AV_WB16(&p->recv[2], fof2); /* length */
739 p->recv[4]=0; /* stream number */
740 p->recv[5]=stream;
742 p->recv[10] &= 0xfe; /* streambox seems to do that... */
744 p->packet++;
746 p->recv_size=fof1;
748 return fof1;
751 // pnm_t *pnm_connect(const char *mrl) {
752 static pnm_t *pnm_connect(int fd, char *path) {
754 pnm_t *p=malloc(sizeof(pnm_t));
755 int need_response=0;
757 p->path=strdup(path);
758 p->s=fd;
760 pnm_send_request(p,pnm_available_bandwidths[10]);
761 if (!pnm_get_headers(p, &need_response)) {
762 mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: failed to set up stream\n");
763 free(p->path);
764 free(p);
765 return NULL;
767 if (need_response)
768 pnm_send_response(p, pnm_response);
769 p->ts_last[0]=0;
770 p->ts_last[1]=0;
772 /* copy header to recv */
774 memcpy(p->recv, p->header, p->header_len);
775 p->recv_size = p->header_len;
776 p->recv_read = 0;
778 return p;
781 static int pnm_read (pnm_t *this, char *data, int len) {
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 int retval;
789 if (len < 0) return 0;
790 while (to_copy > fill) {
792 memcpy(dest, source, fill);
793 to_copy -= fill;
794 dest += fill;
795 this->recv_read=0;
797 if ((retval = pnm_get_stream_chunk (this)) <= 0) {
798 #ifdef LOG
799 mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: %d of %d bytes provided\n", len-to_copy, len);
800 #endif
801 if (retval < 0)
802 return retval;
803 else
804 return len-to_copy;
806 source = this->recv;
807 fill = this->recv_size - this->recv_read;
810 memcpy(dest, source, to_copy);
811 this->recv_read += to_copy;
813 #ifdef LOG
814 mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: %d bytes provided\n", len);
815 #endif
817 return len;
820 static int pnm_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) {
821 return pnm_read(stream_ctrl->data, buffer, size);
824 static int open_s(stream_t *stream,int mode, void* opts, int* file_format) {
825 int fd;
826 pnm_t *pnm;
827 URL_t *url;
829 mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_PNM, URL: %s\n", stream->url);
830 stream->streaming_ctrl = streaming_ctrl_new();
831 if(stream->streaming_ctrl==NULL)
832 return STREAM_ERROR;
834 stream->streaming_ctrl->bandwidth = network_bandwidth;
835 url = url_new(stream->url);
836 stream->streaming_ctrl->url = check4proxies(url);
837 //url_free(url);
839 fd = connect2Server( stream->streaming_ctrl->url->hostname,
840 stream->streaming_ctrl->url->port ? stream->streaming_ctrl->url->port : 7070,1 );
842 if(fd<0)
843 goto fail;
845 pnm = pnm_connect(fd,stream->streaming_ctrl->url->file);
846 if(!pnm)
847 goto fail;
848 stream->type = STREAMTYPE_STREAM;
849 stream->fd=fd;
850 stream->streaming_ctrl->data=pnm;
851 stream->streaming_ctrl->streaming_read = pnm_streaming_read;
852 //stream->streaming_ctrl->streaming_seek = nop_streaming_seek;
853 stream->streaming_ctrl->prebuffer_size = 8*1024; // 8 KBytes
854 stream->streaming_ctrl->buffering = 1;
855 stream->streaming_ctrl->status = streaming_playing_e;
856 *file_format = DEMUXER_TYPE_REAL;
857 fixup_network_stream_cache(stream);
858 return STREAM_OK;
860 fail:
861 streaming_ctrl_free(stream->streaming_ctrl);
862 stream->streaming_ctrl = NULL;
863 return STREAM_UNSUPPORTED;
867 const stream_info_t stream_info_pnm = {
868 "RealNetworks pnm",
869 "pnm",
870 "Arpi, xine team",
871 "ported from xine",
872 open_s,
873 {"pnm", NULL}, //pnm as fallback
874 NULL,
875 0 // Urls are an option string