📄 dvbstream.c
字号:
/* dvbstream - RTP-ize a DVB transport stream.(C) Dave Chapman <dave@dchapman.com> 2001, 2002.The latest version can be found at http://www.linuxstb.org/dvbstreamCopyright notice:This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or(at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */// Linux includes:#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <sys/ioctl.h>#include <sys/time.h>#include <sys/poll.h>#include <sys/stat.h>#include <resolv.h>#include <fcntl.h>#include <unistd.h>#include <signal.h>#include <values.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>// DVB includes:#ifdef NEWSTRUCT#include <linux/dvb/dmx.h>#include <linux/dvb/frontend.h>#else#include <ost/dmx.h>#include <ost/sec.h>#include <ost/frontend.h>#endif#include "rtp.h"#include "mpegtools/transform.h"#include "mpegtools/remux.h"#include "tune.h"// The default telnet port.#define DEFAULT_PORT 12345#define USAGE "\nUSAGE: dvbstream tpid1 tpid2 tpid3 .. tpid8\n\n"#define PACKET_SIZE 188// How often (in seconds) to update the "now" variable#define ALARM_TIME 5/* Thanks to Giancarlo Baracchino for this fix */#define MTU 1500#define IP_HEADER_SIZE 20#define UDP_HEADER_SIZE 8#define RTP_HEADER_SIZE 12#define MAX_RTP_SIZE (MTU-IP_HEADER_SIZE-UDP_HEADER_SIZE-RTP_HEADER_SIZE)#define writes(f,x) write((f),(x),strlen(x))/* Signal handling code shamelessly copied from VDR by Klaus Schmidinger - see http://www.cadsoft.de/people/kls/vdr/index.htm */#ifdef NEWSTRUCTchar* frontenddev[4]={"/dev/dvb/adapter0/frontend0","/dev/dvb/adapter1/frontend0","/dev/dvb/adapter2/frontend0","/dev/dvb/adapter3/frontend0"};char* dvrdev[4]={"/dev/dvb/adapter0/dvr0","/dev/dvb/adapter1/dvr0","/dev/dvb/adapter2/dvr0","/dev/dvb/adapter3/dvr0"};char* demuxdev[4]={"/dev/dvb/adapter0/demux0","/dev/dvb/adapter1/demux0","/dev/dvb/adapter2/demux0","/dev/dvb/adapter3/demux0"};#elsechar* frontenddev[4]={"/dev/ost/frontend0","/dev/ost/frontend1","/dev/ost/frontend2","/dev/ost/frontend3"};char* dvrdev[4]={"/dev/ost/dvr0","/dev/ost/dvr1","/dev/ost/dvr2","/dev/ost/dvr3"};char* secdev[4]={"/dev/ost/sec0","/dev/ost/sec1","/dev/ost/sec2","/dev/ost/sec3"};char* demuxdev[4]={"/dev/ost/demux0","/dev/ost/demux1","/dev/ost/demux2","/dev/ost/demux3"};#endifint card=0;long now;long real_start_time;int Interrupted=0;fe_spectral_inversion_t specInv=INVERSION_AUTO;int tone=-1;fe_modulation_t modulation=CONSTELLATION_DEFAULT;fe_transmit_mode_t TransmissionMode=TRANSMISSION_MODE_DEFAULT;fe_bandwidth_t bandWidth=BANDWIDTH_DEFAULT;fe_guard_interval_t guardInterval=GUARD_INTERVAL_DEFAULT;fe_code_rate_t HP_CodeRate=HP_CODERATE_DEFAULT;unsigned int diseqc=0;char pol=0;int open_fe(int* fd_frontend,int* fd_sec) { if((*fd_frontend = open(frontenddev[card],O_RDWR)) < 0){ perror("FRONTEND DEVICE: "); return -1; }#ifdef NEWSTRUCT fd_sec=0;#else if (fd_sec!=0) { if((*fd_sec = open(secdev[card],O_RDWR)) < 0){ perror("SEC DEVICE: "); return -1; } }#endif return 1;}static void SignalHandler(int signum) { struct timeval tv; if (signum == SIGALRM) { gettimeofday(&tv,(struct timezone*) NULL); now=tv.tv_sec-real_start_time; // fprintf(stderr,"now=%ld\n",now); alarm(ALARM_TIME); } else if (signum != SIGPIPE) { Interrupted=signum; } signal(signum,SignalHandler);}long getmsec() { struct timeval tv; gettimeofday(&tv,(struct timezone*) NULL); return(tv.tv_sec%1000000)*1000 + tv.tv_usec/1000;}// There seems to be a limit of 8 simultaneous filters in the driver#ifdef NEWSTRUCT #define MAX_CHANNELS 16#else #define MAX_CHANNELS 8#endifvoid set_ts_filt(int fd,uint16_t pid, dmx_pes_type_t pestype){ struct dmx_pes_filter_params pesFilterParams; fprintf(stderr,"Setting filter for PID %d\n",pid); pesFilterParams.pid = pid; pesFilterParams.input = DMX_IN_FRONTEND; pesFilterParams.output = DMX_OUT_TS_TAP;#ifdef NEWSTRUCT pesFilterParams.pes_type = pestype;#else pesFilterParams.pesType = pestype;#endif pesFilterParams.flags = DMX_IMMEDIATE_START; if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { fprintf(stderr,"FILTER %i: ",pid); perror("DMX SET PES FILTER"); }}void make_nonblock(int f) { int oldflags; if ((oldflags=fcntl(f,F_GETFL,0)) < 0) { perror("F_GETFL"); } oldflags|=O_NONBLOCK; if (fcntl(f,F_SETFL,oldflags) < 0) { perror("F_SETFL"); }}typedef enum {STREAM_ON,STREAM_OFF} state_t; int socketIn, ns; int pids[MAX_CHANNELS]; int pestypes[MAX_CHANNELS]; unsigned char hi_mappids[8192]; unsigned char lo_mappids[8192]; int fd_sec; int fd_frontend; int pid,pid2; int connectionOpen; int fromlen; char hostname[64]; char in_ch; struct hostent *hp; struct sockaddr_in name, fsin; int ReUseAddr=1; int oldflags; int npids = 0; int fd[MAX_CHANNELS]; int to_stdout = 0; /* to stdout instead of rtp stream */ /* rtp */ struct rtpheader hdr; struct sockaddr_in sOut; int socketOut; ipack pa, pv;#define IPACKS 2048#define TS_SIZE 188#define IN_SIZE TS_SIZEint process_telnet() { char cmd[1024]; int cmd_i=0; int i; char* ch; dmx_pes_type_t pestype; unsigned long freq=0; unsigned long srate=0; /* Open a new telnet session if a client is trying to connect */ if (ns==-1) { if ((ns = accept(socketIn, (struct sockaddr *)&fsin, &fromlen)) > 0) { make_nonblock(ns); cmd_i=0; cmd[0]=0; printf("Opened connection\n"); writes(ns,"220-DVBSTREAM - "); writes(ns,hostname); writes(ns,"\r\nDONE\r\n"); connectionOpen=1; } } /* If a telnet session is open, receive and process any input */ if (connectionOpen) { /* Read in at most a line of text - any ctrl character ends the line */ while (read(ns,&in_ch,1)>0) { if (in_ch < 32) break; /* Prevent buffer overflows */ if (cmd_i < 1024-1) { cmd[cmd_i++]=in_ch; cmd[cmd_i]=0; } } if (in_ch > 0) { if (cmd_i > 0) { printf("CMD: \"%s\"\n",cmd); if (strcasecmp(cmd,"QUIT")==0) { writes(ns,"DONE\r\n"); close(ns); ns=-1; connectionOpen=0; printf("Closed connection\n"); } else if (strcasecmp(cmd,"STOP")==0) { writes(ns,"STOP\n"); for (i=0;i<npids;i++) { if (ioctl(fd[i], DMX_STOP) < 0) { perror("DMX_STOP"); } } for (i=0;i<8192;i++) { hi_mappids[i]=(i >> 8); lo_mappids[i]=(i&0xff); } writes(ns,"DONE\r\n"); } else if (strncasecmp(cmd,"ADD",3)==0) { i=4; if ((cmd[3]=='V') || (cmd[3]=='v')) pestype=DMX_PES_VIDEO; else if ((cmd[3]=='A') || (cmd[3]=='a')) pestype=DMX_PES_AUDIO; else if ((cmd[3]=='T') || (cmd[3]=='t')) pestype=DMX_PES_TELETEXT; else { pestype=DMX_PES_OTHER; i=3; } while (cmd[i]==' ') i++; if ((ch=(char*)strstr(&cmd[i],":"))!=NULL) { pid2=atoi(&ch[1]); ch[0]=0; } else { pid2=-1; } pid=atoi(&cmd[i]); if (pid) { if (npids == MAX_CHANNELS) { fprintf(stderr,"\nsorry, you can only set up to 8 filters.\n\n"); return(-1); } else { pestypes[npids]=pestype; pestype=DMX_PES_OTHER; pids[npids]=pid; if (pid2!=-1) { hi_mappids[pid]=pid2>>8; lo_mappids[pid]=pid2&0xff; fprintf(stderr,"Mapping %d to %d\n",pid,pid2); } if((fd[npids] = open(demuxdev[card],O_RDWR)) < 0){ fprintf(stderr,"FD %i: ",i); perror("DEMUX DEVICE: "); } else { set_ts_filt(fd[npids],pids[npids],pestypes[npids]); npids++; } } } writes(ns,"DONE\r\n"); } else if (strcasecmp(cmd,"START")==0) { writes(ns,"START\n"); for (i=0;i<npids;i++) { set_ts_filt(fd[i],pids[i],pestypes[i]); } writes(ns,"DONE\r\n"); } else if (strncasecmp(cmd,"TUNE",4)==0) { for (i=0;i<8192;i++) { hi_mappids[i]=(i >> 8); lo_mappids[i]=(i&0xff); } for (i=0;i<npids;i++) { if (ioctl(fd[i], DMX_STOP) < 0) { perror("DMX_STOP"); close(fd[i]); } } npids=0; i=4; while (cmd[i]==' ') i++; freq=atoi(&cmd[i])*1000UL; while ((cmd[i]!=' ') && (cmd[i]!=0)) i++; if (cmd[i]!=0) { while (cmd[i]==' ') i++; pol=cmd[i]; while ((cmd[i]!=' ') && (cmd[i]!=0)) i++; if (cmd[i]!=0) { while (cmd[i]==' ') i++; srate=atoi(&cmd[i])*1000UL; fprintf(stderr,"Tuning to %ld,%ld,%c\n",freq,srate,pol); tune_it(fd_frontend,fd_sec,freq,srate,pol,tone,specInv,diseqc,modulation,HP_CodeRate,TransmissionMode,guardInterval,bandWidth); } } } cmd_i=0; cmd[0]=0; writes(ns,"DONE\r\n"); } } } return(0);}/* The output routine for sending a PS */void my_write_out(uint8_t *buf, int count,void *p){ /* to fix: change this buffer size and check for overflow */ static uint8_t out_buffer[1000000]; static int out_buffer_n=0; int i; if (to_stdout) { /* This one is easy. */ write(STDOUT_FILENO, buf, count); } else { /* We are streaming it. */ /* Copy data to write to the end of out_buffer */ memcpy(&out_buffer[out_buffer_n],buf,count); out_buffer_n+=count; /* Send as many full packets as possible */ i=0; while ((i + MAX_RTP_SIZE) < out_buffer_n) { hdr.timestamp = getmsec()*90; sendrtp2(socketOut,&sOut,&hdr,&out_buffer[i],MAX_RTP_SIZE); i+=MAX_RTP_SIZE; } /* Move whatever data is left to the start of the buffer */ memmove(&out_buffer[0],&out_buffer[i],out_buffer_n-i); out_buffer_n-=i; }}void my_ts_to_ps( uint8_t* buf, uint16_t pida, uint16_t pidv){ uint16_t pid; ipack *p; uint8_t off = 0; pid = get_pid(buf+1); if (!(buf[3]&0x10)) // no payload? return; if (pid == pidv){ p = &pv; } else { if (pid == pida){ p = &pa; } else return; } if ( buf[1]&0x40) { if (p->plength == MMAX_PLENGTH-6){ p->plength = p->found-6; p->found = 0; send_ipack(p); reset_ipack(p); } } if ( buf[3] & 0x20) { // adaptation field? off = buf[4] + 1; } instant_repack(buf+4+off, TS_SIZE-4-off, p);}typedef struct { char *filename; int fd; int pids[MAX_CHANNELS]; int num; long start_time; // in seconds long end_time; // in seconds} pids_map_t;pids_map_t *pids_map;int map_cnt;int main(int argc, char **argv){ // state_t state=STREAM_OFF; unsigned short int port=DEFAULT_PORT; int fd_dvr; int i,j; unsigned char buf[MTU]; struct pollfd pfds[2]; // DVR device and Telnet connection unsigned int secs = 0; unsigned long freq=0; unsigned long srate=0; int count; char* ch; dmx_pes_type_t pestype; int bytes_read; int do_analyse=0; unsigned char* free_bytes; int output_type=RTP_TS; int64_t counts[8192]; double f; long start_time=-1; long end_time=-1; struct timeval tv; /* Output: {uni,multi,broad}cast socket */ char ipOut[20]; int portOut; int ttl; pids_map = NULL; map_cnt = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -