📄 pnm.c
字号:
c+=pnm_write_chunk(0x10,0,NULL,&p->buffer[c]); c+=pnm_write_chunk(0x15,0,NULL,&p->buffer[c]); c+=pnm_write_chunk(0x12,0,NULL,&p->buffer[c]); c+=pnm_write_chunk(PNA_GUID,strlen(pnm_guid), pnm_guid,&p->buffer[c]); c+=pnm_write_chunk(PNA_TWENTYFOUR,PNM_TWENTYFOUR_SIZE, pnm_twentyfour,&p->buffer[c]); /* data after chunks */ memcpy(&p->buffer[c],after_chunks,after_chunks_length); c+=after_chunks_length; /* client id string */ p->buffer[c]=PNA_CLIENT_STRING; i16=BE_16D((strlen(client_string)-1)); /* don't know why do we have -1 here */ memcpy(&p->buffer[c+1],&i16,2); memcpy(&p->buffer[c+3],client_string,strlen(client_string)+1); c=c+3+strlen(client_string)+1; /* file path */ p->buffer[c]=0; p->buffer[c+1]=PNA_PATH_REQUEST; i16=BE_16D(strlen(p->path)); memcpy(&p->buffer[c+2],&i16,2); memcpy(&p->buffer[c+4],p->path,strlen(p->path)); c=c+4+strlen(p->path); /* some trailing bytes */ p->buffer[c]='y'; p->buffer[c+1]='B'; rm_write(p->s,p->buffer,c+2);}/* * pnm_send_response sends a response of a challenge */static void pnm_send_response(pnm_t *p, const char *response) { int size=strlen(response); p->buffer[0]=0x23; p->buffer[1]=0; p->buffer[2]=(unsigned char) size; memcpy(&p->buffer[3], response, size); rm_write (p->s, p->buffer, size+3);}/* * get headers and challenge and fix headers * write headers to p->header * write challenge to p->buffer * * return 0 on error. != 0 on success */static int pnm_get_headers(pnm_t *p, int *need_response) { uint32_t chunk_type; uint8_t *ptr=p->header; uint8_t *prop_hdr=NULL; int chunk_size,size=0; int nr;/* rmff_header_t *h; */ *need_response=0; while(1) { if (HEADER_SIZE-size<=0) { mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: header buffer overflow. exiting\n"); return 0; } chunk_size=pnm_get_chunk(p,HEADER_SIZE-size,&chunk_type,ptr,&nr); if (chunk_size < 0) return 0; if (chunk_type == 0) break; if (chunk_type == PNA_TAG) { memcpy(ptr, rm_header, RM_HEADER_SIZE); chunk_size=RM_HEADER_SIZE; *need_response=nr; } if (chunk_type == DATA_TAG) chunk_size=0; if (chunk_type == RMF_TAG) chunk_size=0; if (chunk_type == PROP_TAG) prop_hdr=ptr; size+=chunk_size; ptr+=chunk_size; } if (!prop_hdr) { mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: error while parsing headers.\n"); return 0; } /* set data offset */ size--; prop_hdr[42]=(size>>24)%0xff; prop_hdr[43]=(size>>16)%0xff; prop_hdr[44]=(size>>8)%0xff; prop_hdr[45]=(size)%0xff; size++; /* read challenge */ memcpy (p->buffer, ptr, PREAMBLE_SIZE); rm_read (p->s, &p->buffer[PREAMBLE_SIZE], 64); /* now write a data header */ memcpy(ptr, pnm_data_header, PNM_DATA_HEADER_SIZE); size+=PNM_DATA_HEADER_SIZE;/* h=rmff_scan_header(p->header); rmff_fix_header(h); p->header_len=rmff_get_header_size(h); rmff_dump_header(h, p->header, HEADER_SIZE);*/ p->header_len=size; return 1;}/* * determine correct stream number by looking at indices */static int pnm_calc_stream(pnm_t *p) { char str0=0,str1=0; /* looking at the first index to * find possible stream types */ if (p->seq_current[0]==p->seq_num[0]) str0=1; if (p->seq_current[0]==p->seq_num[2]) str1=1; switch (str0+str1) { case 1: /* one is possible, good. */ if (str0) { p->seq_num[0]++; p->seq_num[1]=p->seq_current[1]+1; return 0; } else { p->seq_num[2]++; p->seq_num[3]=p->seq_current[1]+1; return 1; } break; case 0: case 2: /* both types or none possible, not so good */ /* try to figure out by second index */ if ( (p->seq_current[1] == p->seq_num[1]) &&(p->seq_current[1] != p->seq_num[3])) { /* ok, only stream0 matches */ p->seq_num[0]=p->seq_current[0]+1; p->seq_num[1]++; return 0; } if ( (p->seq_current[1] == p->seq_num[3]) &&(p->seq_current[1] != p->seq_num[1])) { /* ok, only stream1 matches */ p->seq_num[2]=p->seq_current[0]+1; p->seq_num[3]++; return 1; } /* wow, both streams match, or not. */ /* now we try to decide by timestamps */ if (p->ts_current < p->ts_last[1]) return 0; if (p->ts_current < p->ts_last[0]) return 1; /* does not help, we guess type 0 */#ifdef LOG mp_msg(MSGT_OPEN, MSGL_INFO, "guessing stream# 0\n");#endif p->seq_num[0]=p->seq_current[0]+1; p->seq_num[1]=p->seq_current[1]+1; return 0; break; } mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: wow, something very nasty happened in pnm_calc_stream\n"); return 2;}/* * gets a stream chunk and writes it to a recieve buffer */static int pnm_get_stream_chunk(pnm_t *p) { int n; char keepalive='!'; unsigned int fof1, fof2, stream; /* send a keepalive */ /* realplayer seems to do that every 43th package */ if ((p->packet%43) == 42) { rm_write(p->s,&keepalive,1); } /* data chunks begin with: 'Z' <o> <o> <i1> 'Z' <i2> * where <o> is the offset to next stream chunk, * <i1> is a 16 bit index * <i2> is a 8 bit index which counts from 0x10 to somewhere */ n = rm_read (p->s, p->buffer, 8); if (n<0) return -1; if (n<8) return 0; /* skip 8 bytes if 0x62 is read */ if (p->buffer[0] == 0x62) { n = rm_read (p->s, p->buffer, 8); if (n<8) return 0;#ifdef LOG mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: had to seek 8 bytes on 0x62\n");#endif } /* a server message */ if (p->buffer[0] == 'X') { int size=BE_16(&p->buffer[1]); rm_read (p->s, &p->buffer[8], size-5); p->buffer[size+3]=0; mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: got message from server while reading stream:\n%s\n", &p->buffer[3]); return -1; } if (p->buffer[0] == 'F') { mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: server error.\n"); return -1; } /* skip bytewise to next chunk. * seems, that we don't need that, if we send enough * keepalives */ n=0; while (p->buffer[0] != 0x5a) { int i; for (i=1; i<8; i++) { p->buffer[i-1]=p->buffer[i]; } rm_read (p->s, &p->buffer[7], 1); n++; }#ifdef LOG if (n) mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: had to seek %i bytes to next chunk\n", n);#endif /* check for 'Z's */ if ((p->buffer[0] != 0x5a)||(p->buffer[7] != 0x5a)) { mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: bad boundaries\n"); hexdump(p->buffer, 8); return 0; } /* check offsets */ fof1=BE_16(&p->buffer[1]); fof2=BE_16(&p->buffer[3]); if (fof1 != fof2) { mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: frame offsets are different: 0x%04x 0x%04x\n",fof1,fof2); return 0; } /* get first index */ p->seq_current[0]=BE_16(&p->buffer[5]); /* now read the rest of stream chunk */ n = rm_read (p->s, &p->recv[5], fof1-5); if (n<(fof1-5)) return 0; /* get second index */ p->seq_current[1]=p->recv[5]; /* get timestamp */ p->ts_current=BE_32(&p->recv[6]); /* get stream number */ stream=pnm_calc_stream(p); /* saving timestamp */ p->ts_last[stream]=p->ts_current; /* constructing a data packet header */ p->recv[0]=0; /* object version */ p->recv[1]=0; fof2=BE_16(&fof2); memcpy(&p->recv[2], &fof2, 2); /*p->recv[2]=(fof2>>8)%0xff;*/ /* length */ /*p->recv[3]=(fof2)%0xff;*/ p->recv[4]=0; /* stream number */ p->recv[5]=stream; p->recv[10]=p->recv[10] & 0xfe; /* streambox seems to do that... */ p->packet++; p->recv_size=fof1; return fof1;}// pnm_t *pnm_connect(const char *mrl) {static pnm_t *pnm_connect(int fd, char *path) { pnm_t *p=malloc(sizeof(pnm_t)); int need_response=0; p->path=strdup(path); p->s=fd; pnm_send_request(p,pnm_available_bandwidths[10]); if (!pnm_get_headers(p, &need_response)) { mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: failed to set up stream\n"); free(p->path); free(p); return NULL; } if (need_response) pnm_send_response(p, pnm_response); p->ts_last[0]=0; p->ts_last[1]=0; /* copy header to recv */ memcpy(p->recv, p->header, p->header_len); p->recv_size = p->header_len; p->recv_read = 0; return p;}static int pnm_read (pnm_t *this, char *data, int len) { int to_copy=len; char *dest=data; char *source=this->recv + this->recv_read; int fill=this->recv_size - this->recv_read; int retval; if (len < 0) return 0; while (to_copy > fill) { memcpy(dest, source, fill); to_copy -= fill; dest += fill; this->recv_read=0; if ((retval = pnm_get_stream_chunk (this)) <= 0) {#ifdef LOG mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: %d of %d bytes provided\n", len-to_copy, len);#endif if (retval < 0) return retval; else return len-to_copy; } source = this->recv; fill = this->recv_size - this->recv_read; } memcpy(dest, source, to_copy); this->recv_read += to_copy;#ifdef LOG mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: %d bytes provided\n", len);#endif return len;}static int pnm_peek_header (pnm_t *this, char *data) { memcpy (data, this->header, this->header_len); return this->header_len;}static void pnm_close(pnm_t *p) { if (p->s >= 0) closesocket(p->s); free(p->path); free(p);}static int pnm_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) { return pnm_read(stream_ctrl->data, buffer, size);}static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { int fd; pnm_t *pnm; URL_t *url; mp_msg(MSGT_OPEN, MSGL_INFO, "STREAM_PNM, URL: %s\n", stream->url); stream->streaming_ctrl = streaming_ctrl_new(); if(stream->streaming_ctrl==NULL) { return STREAM_ERROR; } stream->streaming_ctrl->bandwidth = network_bandwidth; url = url_new(stream->url); stream->streaming_ctrl->url = check4proxies(url); //url_free(url); fd = connect2Server( stream->streaming_ctrl->url->hostname, stream->streaming_ctrl->url->port ? stream->streaming_ctrl->url->port : 7070,1 ); if(fd<0) goto fail; pnm = pnm_connect(fd,stream->streaming_ctrl->url->file); if(!pnm) goto fail; stream->type = STREAMTYPE_STREAM; stream->fd=fd; stream->streaming_ctrl->data=pnm; stream->streaming_ctrl->streaming_read = pnm_streaming_read; //stream->streaming_ctrl->streaming_seek = nop_streaming_seek; stream->streaming_ctrl->prebuffer_size = 8*1024; // 8 KBytes stream->streaming_ctrl->buffering = 1; stream->streaming_ctrl->status = streaming_playing_e; *file_format = DEMUXER_TYPE_REAL; fixup_network_stream_cache(stream); return STREAM_OK;fail: streaming_ctrl_free(stream->streaming_ctrl); stream->streaming_ctrl = NULL; return STREAM_UNSUPPORTED;}stream_info_t stream_info_pnm = { "RealNetworks pnm", "pnm", "Arpi, xine team", "ported from xine", open_s, {"pnm", NULL}, //pnm as fallback NULL, 0 // Urls are an option string};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -