⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtpplay.c

📁 RTP 实现的工具
💻 C
字号:
/** Recreate packet stream recorded with rtpdump -f dump.* Usage:* -v         verbose* -T         use absolute time rather than RTP timestamps* -f         file to read* -p [file]  profile of RTP PT to frequency mappings** Program reads ahead by READAHEAD packets to compensate for reordering.* Currently does not correct SR/RR absolute (NTP) timestamps,* but should. Receiver reports are fairly meaningless.** (c) 1994-1996 Henning Schulzrinne*/#include <stdio.h>#include <sys/types.h>#include <sys/time.h>    /* gettimeofday() */#include <sys/socket.h>  /* struct sockaddr */#include <netinet/in.h>#include <arpa/inet.h>   /* inet_ntoa() */#include <time.h>#include <stdio.h>       /* stderr, printf() */#include <string.h>#include <stdlib.h>      /* perror() */#include <unistd.h>      /* write() */#include <search.h>      /* hash table */#include "notify.h"      /* notify_start(), ... */#include "rtp.h"         /* RTP headers */#include "types.h"#include "rtpdump.h"     /* RD_packet_t */#include "multimer.h"    /* timer_set() */#include "ansi.h"#define READAHEAD 16 /* must be power of 2 */static char rcsid[] = "$Id: rtpplay.c,v 1.2 1995/08/30 11:19:01 hgs Exp $";static int verbose = 0;     /* be chatty about packets sent */static int wallclock = 0;   /* use wallclock time rather than timestamps */static FILE *in = stdin;    /* input file */static int sock[2];         /* output sockets */static int first = -1;      /* offset of first packet */static RD_buffer_t buffer[READAHEAD];static double period[128] = {  /* ms per timestamp difference */  1/8000.,   /*  0: PCMU */  1/8000.,   /*  1: 1016 */  1/8000.,   /*  2: G721 */  1/8000.,   /*  3: GSM  */  1/8000.,   /*  4: G723 */  1/8000.,   /*  5: DVI4 */  1/16000.,  /*  6: DVI4 */  1/8000.,   /*  7: LPC  */  1/8000.,   /*  8: PCMA */  1/16000.,  /*  9: G722 */  1/44100.,  /* 10: L16  */  1/44100.,  /* 11: L16  */  0,         /* 12:      */  0,         /* 13:      */  1/90000.,  /* 14: MPA  */  1/90000.,  /* 15: G728 */  1/11025.,  /* 16: DVI4 */  1/22050.,  /* 17: DVI4 */  0,         /* 18:      */  0,         /* 19:      */  0,         /* 20:      */  0,         /* 21:      */  0,         /* 22:      */  0,         /* 23:      */  0,         /* 24:      */  1/90000.,  /* 25: CelB */  1/90000.,  /* 26: JPEG */    1/90000.,  /* 27:      */    1/90000.,  /* 28: nv   */    1/90000.,  /* 29:      */    1/90000.,  /* 30: */    1/90000.,  /* 31: H261 */    1/90000.,  /* 32: MPV  */    1/90000.,  /* 33: MP2T */    1/90000.,  /* 34: H263 */};static void usage(char *argv0){  fprintf(stderr,"Usage: %s [-v] [-T] [-p profile] [-f file] destination/port[/ttl]\n",  argv0);  exit(1);} /* usage */static double tdbl(struct timeval *a){  return a->tv_sec + a->tv_usec/1e6;}/** Transmit RTP/RTCP packet on output socket and mark as read.*/static void play_transmit(int b){  if (b >= 0 && buffer[b].p.hdr.length) {    if (write(sock[buffer[b].p.hdr.plen == 0],        buffer[b].p.data, buffer[b].p.hdr.length) < 0) {      perror("write");    }     buffer[b].p.hdr.length = 0;  }} /* play_transmit *//** Timer handler: read next record from file and insert into timer* handler.*/static Notify_value play_handler(Notify_client client){  static struct timeval start;  /* generation time of first played back p. */  struct timeval now;           /* current time */  struct timeval next;          /* next packet generation time */  ENTRY *e;                     /* hash table entry */  struct rt_ts {    struct timeval rt;          /* real-time */    unsigned long ts;           /* timestamp */  };  struct rt_ts *t = 0;  char ssrc[12];  u_int32 ts  = 0;  u_int8  pt  = 0;  u_int16 seq = 0;  u_int8  m   = 0;  rtp_hdr_t *r;  int b = (int)client;  /* buffer to be played now */  int rp;        /* read pointer */  gettimeofday(&now, 0);  /* playback scheduled packet */  play_transmit(b);  if (verbose > 0 && b >= 0) {    printf("%1.3f %s(%3d;%3d) t=%6lu",      tdbl(&now), buffer[b].p.hdr.plen ? "RTP " : "RTCP",      buffer[b].p.hdr.length, buffer[b].p.hdr.plen,      (unsigned long)buffer[b].p.hdr.offset);    if (buffer[b].p.hdr.plen) {      r = (rtp_hdr_t *)buffer[b].p.data;      printf(" ssrc=%8lx %cts=%9ld seq=%5d",        ntohl(r->ssrc), r->m ? '*' : ' ',        ntohl(r->ts), ntohs(r->seq));    }    printf("\n");  }  /* find available buffer */  for (rp = 0; rp < READAHEAD; rp++) {    if (!buffer[rp].p.hdr.length) break;  }  /* get next packet */  RD_read(in, &buffer[rp]);  r = (rtp_hdr_t *)buffer[rp].p.data;  if (buffer[rp].p.hdr.plen && r->version == 2 && !wallclock) {    ENTRY item;    ts  = ntohl(r->ts);    seq = ntohs(r->seq);    pt  = r->pt;    m   = r->m;    sprintf(ssrc, "%lx", ntohl(r->ssrc));    /* find hash entry */    item.key  = ssrc;    item.data = 0;    e = hsearch(item, FIND);    /* if found, compute playout instant */    if (e) {      double d;      t = (struct rt_ts *)e->data;      d = period[pt] * (int)(ts - t->ts);      next.tv_sec  = t->rt.tv_sec  + (int)d;      next.tv_usec = t->rt.tv_usec + (d - (int)d) * 1000000;      printf("%1.3f rp=%d b=%d d=%f\n", tdbl(&next), rp, b, d);    } else { /* if none, insert and play now */      item.key  = malloc(strlen(ssrc)+1);      strcpy(item.key, ssrc);      item.data = (void *)t = (struct rt_ts *)malloc(sizeof(struct rt_ts));      next = now;      e = hsearch(item, ENTER);    }  }  /* RTCP or vat or playing back by wallclock */  else {    if (first < 0) {      start = now;      first = buffer[rp].p.hdr.offset;    }    /* compute next playout time */    buffer[rp].p.hdr.offset -= first;    next.tv_sec  = start.tv_sec  + buffer[rp].p.hdr.offset/1000;    next.tv_usec = start.tv_usec + (buffer[rp].p.hdr.offset%1000) * 1000;    ssrc[0] = '\0';  }  if (next.tv_usec > 1000000) {    next.tv_usec -= 1000000;    next.tv_sec  += 1;  }  /* save correct value in record (for timestamp-based playback) */  if (t) {    t->rt = next;    t->ts = ts;   }  timer_set(&next, play_handler, (Notify_client)rp, 0);  return NOTIFY_DONE;} /* play_handler *//** Read profile file, containing one line for each PT.*/static void profile(char *fn){  FILE *f;  int pt, r;  if (!(f = fopen(fn, "r"))) {    perror(fn);    exit(1);  }  while (fscanf(f, "%d %d", &pt, &r) != EOF) {    if (pt >= 0 && pt < 128 && r > 0 && r < 100000) {      period[pt] = 1/(double)r;    }    else {      fprintf(stderr, "PT=%d or rate=%d is invalid.\n", pt, r);    }  }} /* profile */int main(int argc, char *argv[]){  char ttl = 1;  static struct sockaddr_in sin;  int i;  int c;  extern char *optarg;  extern int optind;  extern int hpt(char *h, struct sockaddr *sa, unsigned char *ttl);  /* parse command line arguments */  while ((c = getopt(argc, argv, "f:p:Tv")) != EOF) {    switch(c) {    case 'f':      if (!(in = fopen(optarg, "r"))) {        perror(optarg);        exit(1);      }      break;    case 'p':      profile(optarg);      break;    case 'T':      wallclock = 1;      break;    case 'v':      verbose = 1;      break;    case '?':    case 'h':      usage(argv[0]);      break;    }  }  if (optind < argc) {    if (hpt(argv[optind], (struct sockaddr *)&sin, &ttl) < 0) {      usage(argv[0]);    }  }  /* read header of input file */  if (RD_header(in, &sin, 0) < 0) {    fprintf(stderr, "Invalid header\n");    exit(1);  }  /* create/connect sockets if they don't exist already */  if (!sock[0]) {    for (i = 0; i < 2; i++) {      sock[i] = socket(PF_INET, SOCK_DGRAM, 0);      if (sock[i] < 0) {        perror("socket");        exit(1);      }      sin.sin_port = htons(ntohs(sin.sin_port) + i);      if (connect(sock[i], (struct sockaddr *)&sin, sizeof(sin)) < 0) {        perror("connect");        exit(1);      }      if (IN_CLASSD(ntohl(sin.sin_addr.s_addr)) &&           (setsockopt(sock[i], IPPROTO_IP, IP_MULTICAST_TTL, &ttl,                   sizeof(ttl)) < 0)) {        perror("IP_MULTICAST_TTL");        exit(1);      }    }  }  /* initialize event queue */  first = -1;  hcreate(100); /* create hash table for SSRC entries */  for (i = 0; i < READAHEAD; i++) play_handler(-1);  notify_start();  hdestroy();  return 0;} /* main */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -