📄 pnm.c
字号:
/* * Copyright (C) 2000-2002 the xine project * * This file is part of xine, a free video player. * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * $Id: pnm.c,v 1.3 2008/04/12 07:14:45 dsqiu Exp $ * * pnm protocol implementation * based upon code from joschka */#include "config.h"#include <mplaylib.h>#include <mplaylib.h>#include <assert.h>#include <mplaylib.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#include <mplaylib.h>#include <sys/time.h>#include <inttypes.h>#ifndef HAVE_WINSOCK2#define closesocket close#include <sys/socket.h>//#include <netinet/in.h>//#include <netdb.h>#else#include <winsock2.h>#endif#include "stream.h"#include "libmpdemux/demuxer.h"#include "help_mp.h"#include "osdep/timer.h"#include "pnm.h"#include "tcp.h"//#include "libreal/rmff.h"#undef memcpy#define memcpy uc_memcpyextern int network_bandwidth;#define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \ (((long)(unsigned char)(ch3) ) | \ ( (long)(unsigned char)(ch2) << 8 ) | \ ( (long)(unsigned char)(ch1) << 16 ) | \ ( (long)(unsigned char)(ch0) << 24 ) )#define RMF_TAG FOURCC_TAG('.', 'R', 'M', 'F')#define PROP_TAG FOURCC_TAG('P', 'R', 'O', 'P')#define MDPR_TAG FOURCC_TAG('M', 'D', 'P', 'R')#define CONT_TAG FOURCC_TAG('C', 'O', 'N', 'T')#define DATA_TAG FOURCC_TAG('D', 'A', 'T', 'A')#define INDX_TAG FOURCC_TAG('I', 'N', 'D', 'X')#define PNA_TAG FOURCC_TAG('P', 'N', 'A', 0 )/*#define LOG*/#define BUF_SIZE 4096#define HEADER_SIZE 4096struct pnm_s { int s;// char *host;// int port; char *path;// char *url; char buffer[BUF_SIZE]; /* scratch buffer */ /* receive buffer */ uint8_t recv[BUF_SIZE]; int recv_size; int recv_read; uint8_t header[HEADER_SIZE]; int header_len; int header_read; unsigned int seq_num[4]; /* two streams with two indices */ unsigned int seq_current[2]; /* seqs of last stream chunk read */ uint32_t ts_current; /* timestamp of current chunk */ uint32_t ts_last[2]; /* timestamps of last chunks */ unsigned int packet; /* number of last recieved packet */};/* * utility macros */#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1])#define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ (((uint8_t*)(x))[1] << 16) | \ (((uint8_t*)(x))[2] << 8) | \ ((uint8_t*)(x))[3])/* D means direct (no pointer) */#define BE_16D(x) ((x & 0xff00) >> 8)|((x & 0x00ff) << 8)/* sizes */#define PREAMBLE_SIZE 8#define CHECKSUM_SIZE 3/* header of rm files */#define RM_HEADER_SIZE 0x12static const unsigned char rm_header[]={ 0x2e, 0x52, 0x4d, 0x46, /* object_id ".RMF" */ 0x00, 0x00, 0x00, 0x12, /* header_size 0x12 */ 0x00, 0x00, /* object_version 0x00 */ 0x00, 0x00, 0x00, 0x00, /* file_version 0x00 */ 0x00, 0x00, 0x00, 0x06 /* num_headers 0x06 */};/* data chunk header */#define PNM_DATA_HEADER_SIZE 18static const unsigned char pnm_data_header[]={ 'D','A','T','A', 0,0,0,0, /* data chunk size */ 0,0, /* object version */ 0,0,0,0, /* num packets */ 0,0,0,0}; /* next data header *//* pnm request chunk ids */#define PNA_CLIENT_CAPS 0x03#define PNA_CLIENT_CHALLANGE 0x04#define PNA_BANDWIDTH 0x05#define PNA_GUID 0x13#define PNA_TIMESTAMP 0x17#define PNA_TWENTYFOUR 0x18#define PNA_CLIENT_STRING 0x63#define PNA_PATH_REQUEST 0x52static const unsigned char pnm_challenge[] = "0990f6b4508b51e801bd6da011ad7b56";static const unsigned char pnm_timestamp[] = "[15/06/1999:22:22:49 00:00]";static const unsigned char pnm_guid[] = "3eac2411-83d5-11d2-f3ea-d7c3a51aa8b0";static const unsigned char pnm_response[] = "97715a899cbe41cee00dd434851535bf";static const unsigned char client_string[] = "WinNT_9.0_6.0.6.45_plus32_MP60_en-US_686l";#define PNM_HEADER_SIZE 11static const unsigned char pnm_header[] = { 'P','N','A', 0x00, 0x0a, 0x00, 0x14, 0x00, 0x02, 0x00, 0x01 };#define PNM_CLIENT_CAPS_SIZE 126static const unsigned char pnm_client_caps[] = { 0x07, 0x8a, 'p','n','r','v', 0, 0x90, 'p','n','r','v', 0, 0x64, 'd','n','e','t', 0, 0x46, 'p','n','r','v', 0, 0x32, 'd','n','e','t', 0, 0x2b, 'p','n','r','v', 0, 0x28, 'd','n','e','t', 0, 0x24, 'p','n','r','v', 0, 0x19, 'd','n','e','t', 0, 0x18, 'p','n','r','v', 0, 0x14, 's','i','p','r', 0, 0x14, 'd','n','e','t', 0, 0x24, '2','8','_','8', 0, 0x12, 'p','n','r','v', 0, 0x0f, 'd','n','e','t', 0, 0x0a, 's','i','p','r', 0, 0x0a, 'd','n','e','t', 0, 0x08, 's','i','p','r', 0, 0x06, 's','i','p','r', 0, 0x12, 'l','p','c','J', 0, 0x07, '0','5','_','6' };static const uint32_t pnm_default_bandwidth=10485800;static const uint32_t pnm_available_bandwidths[]={14400,19200,28800,33600,34430,57600, 115200,262200,393216,524300,1544000,10485800};#define PNM_TWENTYFOUR_SIZE 16static unsigned char pnm_twentyfour[]={ 0xd5, 0x42, 0xa3, 0x1b, 0xef, 0x1f, 0x70, 0x24, 0x85, 0x29, 0xb3, 0x8d, 0xba, 0x11, 0xf3, 0xd6 };/* now other data follows. marked with 0x0000 at the beginning */static int after_chunks_length=6;static unsigned char after_chunks[]={ 0x00, 0x00, /* mark */ 0x50, 0x84, /* seems to be fixated */ 0x1f, 0x3a /* varies on each request (checksum ?)*/ };static void hexdump (char *buf, int length);static int rm_write(int s, const char *buf, int len) { int total, timeout; total = 0; timeout = 30; while (total < len){ int n; n = send (s, &buf[total], len - total, 0); if (n > 0) total += n; else if (n < 0) {#ifndef HAVE_WINSOCK2 if ((timeout>0) && ((errno == EAGAIN) || (errno == EINPROGRESS))) {#else if ((timeout>0) && ((errno == EAGAIN) || (WSAGetLastError() == WSAEINPROGRESS))) {#endif usec_sleep (1000000); timeout--; } else return -1; } } return total;}static ssize_t rm_read(int fd, void *buf, size_t count) { ssize_t ret, total; total = 0; while (total < count) { fd_set rset; struct timeval timeout; FD_ZERO (&rset); FD_SET (fd, &rset); timeout.tv_sec = 3; timeout.tv_usec = 0; if (select (fd+1, &rset, NULL, NULL, &timeout) <= 0) { return -1; } ret=recv (fd, ((uint8_t*)buf)+total, count-total, 0); if (ret<=0) { mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: read error.\n"); return ret; } else total += ret; } return total;}/* * debugging utilities */ static void hexdump (char *buf, int length) { int i; mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: ascii>"); for (i = 0; i < length; i++) { unsigned char c = buf[i]; if ((c >= 32) && (c <= 128)) mp_msg(MSGT_OPEN, MSGL_INFO, "%c", c); else mp_msg(MSGT_OPEN, MSGL_INFO, "."); } mp_msg(MSGT_OPEN, MSGL_INFO, "\n"); mp_msg(MSGT_OPEN, MSGL_INFO, "input_pnm: hexdump> "); for (i = 0; i < length; i++) { unsigned char c = buf[i]; mp_msg(MSGT_OPEN, MSGL_INFO, "%02x", c); if ((i % 16) == 15) mp_msg(MSGT_OPEN, MSGL_INFO, "\npnm: "); if ((i % 2) == 1) mp_msg(MSGT_OPEN, MSGL_INFO, " "); } mp_msg(MSGT_OPEN, MSGL_INFO, "\n");}/* * pnm_get_chunk gets a chunk from stream * and returns number of bytes read */static int pnm_get_chunk(pnm_t *p, unsigned int max, unsigned int *chunk_type, char *data, int *need_response) { unsigned int chunk_size; unsigned int n; char *ptr; if (max < PREAMBLE_SIZE) return -1; /* get first PREAMBLE_SIZE bytes and ignore checksum */ rm_read (p->s, data, CHECKSUM_SIZE); if (data[0] == 0x72) rm_read (p->s, data, PREAMBLE_SIZE); else rm_read (p->s, data+CHECKSUM_SIZE, PREAMBLE_SIZE-CHECKSUM_SIZE); max -= PREAMBLE_SIZE; *chunk_type = BE_32(data); chunk_size = BE_32(data+4); switch (*chunk_type) { case PNA_TAG: *need_response=0; ptr=data+PREAMBLE_SIZE; if (max < 1) return -1; rm_read (p->s, ptr++, 1); max -= 1; while(1) { /* expecting following chunk format: 0x4f <chunk size> <data...> */ if (max < 2) return -1; rm_read (p->s, ptr, 2); max -= 2; if (*ptr == 'X') /* checking for server message */ { mp_msg(MSGT_OPEN, MSGL_WARN, "input_pnm: got a message from server:\n"); if (max < 1) return -1; rm_read (p->s, ptr+2, 1); max = -1; n=BE_16(ptr+1); if (max < n) return -1; rm_read (p->s, ptr+3, n); max -= n; ptr[3+n]=0; mp_msg(MSGT_OPEN, MSGL_WARN, "%s\n",ptr+3); return -1; } if (*ptr == 'F') /* checking for server error */ { mp_msg(MSGT_OPEN, MSGL_ERR, "input_pnm: server error.\n"); return -1; } if (*ptr == 'i') { ptr+=2; *need_response=1; continue; } if (*ptr != 0x4f) break; n=ptr[1]; if (max < n) return -1; rm_read (p->s, ptr+2, n); max -= n; ptr+=(n+2); } /* the checksum of the next chunk is ignored here */ if (max < 1) return -1; rm_read (p->s, ptr+2, 1); ptr+=3; chunk_size=ptr-data; break; case RMF_TAG: case DATA_TAG: case PROP_TAG: case MDPR_TAG: case CONT_TAG: if (chunk_size > max || chunk_size < PREAMBLE_SIZE) { mp_msg(MSGT_OPEN, MSGL_ERR, "error: max chunk size exceded (max was 0x%04x)\n", max);#ifdef LOG n=rm_read (p->s, &data[PREAMBLE_SIZE], 0x100 - PREAMBLE_SIZE); hexdump(data,n+PREAMBLE_SIZE);#endif return -1; } rm_read (p->s, &data[PREAMBLE_SIZE], chunk_size-PREAMBLE_SIZE); break; default: *chunk_type = 0; chunk_size = PREAMBLE_SIZE; break; } return chunk_size;}/* * writes a chunk to a buffer, returns number of bytes written */static int pnm_write_chunk(uint16_t chunk_id, uint16_t length, const char *chunk, char *data) { data[0]=(chunk_id>>8)%0xff; data[1]=chunk_id%0xff; data[2]=(length>>8)%0xff; data[3]=length%0xff; memcpy(&data[4],chunk,length); return length+4;}/* * constructs a request and sends it */static void pnm_send_request(pnm_t *p, uint32_t bandwidth) { uint16_t i16; int c=PNM_HEADER_SIZE; char fixme[]={0,1}; memcpy(p->buffer,pnm_header,PNM_HEADER_SIZE); c+=pnm_write_chunk(PNA_CLIENT_CHALLANGE,strlen(pnm_challenge), pnm_challenge,&p->buffer[c]); c+=pnm_write_chunk(PNA_CLIENT_CAPS,PNM_CLIENT_CAPS_SIZE, pnm_client_caps,&p->buffer[c]); c+=pnm_write_chunk(0x0a,0,NULL,&p->buffer[c]); c+=pnm_write_chunk(0x0c,0,NULL,&p->buffer[c]); c+=pnm_write_chunk(0x0d,0,NULL,&p->buffer[c]); c+=pnm_write_chunk(0x16,2,fixme,&p->buffer[c]); c+=pnm_write_chunk(PNA_TIMESTAMP,strlen(pnm_timestamp), pnm_timestamp,&p->buffer[c]); c+=pnm_write_chunk(PNA_BANDWIDTH,4, (const char *)&pnm_default_bandwidth,&p->buffer[c]); c+=pnm_write_chunk(0x08,0,NULL,&p->buffer[c]); c+=pnm_write_chunk(0x0e,0,NULL,&p->buffer[c]); c+=pnm_write_chunk(0x0f,0,NULL,&p->buffer[c]); c+=pnm_write_chunk(0x11,0,NULL,&p->buffer[c]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -