> > Somewhere I still have a command line utility which sends out H.263 > > files (written by the tmn encoder) as RTP streams, which I've used for > > testing purposes. > > If you can find it will help me a lot :) Found it. Five years old, and the @cs address doesn't work any more these days ... Gerd ==============================[ rtp.h ]============================== #define RTCP_TYPE_SR 200 #define RTCP_TYPE_RR 201 #define RTCP_TYPE_SDES 202 #define RTCP_TYPE_BYE 203 #define RTCP_TYPE_APP 204 #define RCTP_F_V_MASK 0xc0 #define RCTP_F_P_MASK 0x20 #define RCTP_F_C_MASK 0x1f struct RTCP { unsigned char flags; unsigned char pt; /* packet type */ unsigned short length; unsigned long ssrc; }; /* --------------------------------------------------------------------- */ #define RTP_F_V_MASK 0xc0 #define RTP_F_P_MASK 0x20 #define RTP_F_X_MASK 0x10 #define RTP_F_C_MASK 0x0f #define RTP_PT_M_MASK 0x80 #define RTP_PT_PT_MASK 0x7f struct RTP { unsigned char flags; unsigned char pt; /* packet type + M-bit */ unsigned short seq; unsigned long timestamp; unsigned long ssrc; unsigned long payload[0]; }; ==============================[ send-h263.c ]======================== /* * (c) 1997 Gerd Knorr <kraxel@xxxxxxxxxxxxxxx> * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <signal.h> #include <errno.h> #include <sys/time.h> #include <sys/types.h> #include <sys/utsname.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include "rtp.h" extern char *optarg; #define MAX_PACKET_SIZE 16384 /* ---------------------------------------------------------------------- */ char *name = "send-h263 1.0"; int verbose = 0; int my_port = 4711; char my_addr[128] = "*"; int dest_port = 4711; char dest_addr[128] = "224.0.0.42"; char *filename = NULL; /* size of outgoing pakets */ int send_psize = 1400; /* statistics */ int paket_count = 0; int octet_count = 0; /* ---------------------------------------------------------------------- */ int stop = 0; void catch_signal(int sig) { if (SIGINT == sig) fprintf(stderr,"^C - one moment please...\n"); stop = 1; } /* ---------------------------------------------------------------------- */ void usage(char *prog) { char *h; h = strrchr(prog,'/'); fprintf(stderr, "usage: %s [ options ]\n" "\n" "Options:\n" " -h print this text\n" " -f file read H.263 bitstream from >file<\n" " -a ipaddr send RTP pakets to >ipaddr< [%s]\n" " -p port sent RTP pakets to >port< [%d]\n" " -s size set max. packet size [%d]\n" " -i ipaddr bind locally to >ipaddr< [%s]\n", h ? h+1 : prog, dest_addr, send_psize, dest_port, my_addr); exit(1); } void string_to_ipaddr(char *name, struct sockaddr_in *addr) { struct hostent *host; /* "*" is any address (for bind) */ if (0 == strcmp(name,"*")) { addr->sin_addr.s_addr = htonl (INADDR_ANY); return; } /* try to parse it it dotted number ... */ if (-1 == (addr->sin_addr.s_addr = inet_addr(name))) { /* ... failing that do a DNS lookup */ if (NULL == (host = gethostbyname(name))) { fprintf(stderr,"can't resolve hostname %s\n",name); exit(1); } addr->sin_addr = *(struct in_addr *) host->h_addr; } } void dump_paket(unsigned char *data, int len) { int x,y; for (y = 0; y < len; y += 16) { printf("\t"); for (x = y; x < y+16; x++) { if (x < len) printf("%02x ",data[x]); else printf(" "); } printf(" "); for (x = y; x < y+16; x++) { if (x < len) printf("%c", ((data[x] & 0x7f) < 32) ? '.' : data[x]); else printf(" "); } printf("\n"); } } /* ---------------------------------------------------------------------- */ static char *sdes[] = { "", "user@host", /* cname */ "Gerd Knorr", /* name */ "kraxel@xxxxxxxxxxxxxxx", /* email */ "", /* phone */ "", /* location */ "", /* tool */ "H263v2 RTP payload testing", /* note */ "", /* priv (?) */ NULL }; static char *bye = "end of file"; int build_rtcp(char *packet, int type, unsigned int ssrc, unsigned int timestamp) { struct RTCP *rtcp = (struct RTCP*) packet; unsigned int *l = (unsigned int*) packet; int length,i,n; rtcp->flags = 0x80; rtcp->pt = type; rtcp->ssrc = ssrc; switch (type) { case RTCP_TYPE_SR: l[2] = 0; /* FIXME: ntp timestamp goes here */ l[3] = 0; /* ntp #2 */ l[4] = timestamp; l[5] = paket_count; l[6] = octet_count; length = 4*7; break; case RTCP_TYPE_SDES: rtcp->flags++; length = 8; for (i = 1; sdes[i] != NULL; i++) { if (0 == (n = strlen(sdes[i]))) continue; packet[length] = i; /* type */ packet[length+1] = n; /* length */ memcpy(packet+length+2,sdes[i],n); length += n+2; } break; case RTCP_TYPE_BYE: rtcp->flags++; length = 8; n = strlen(bye); packet[length] = n; memcpy(packet+length+1,bye,n); length += n+1; break; default: length = 8; break; } length = (length+3)&0xfffc; rtcp->length = htons((length/4)-1); return length; } /* ---------------------------------------------------------------------- */ int main(int argc, char *argv[]) { struct sockaddr_in addr,dest; int c,i,n,ps,length; int s_rtp = -1,s_rtcp = -1; unsigned char *packet,*buffer,*user; struct utsname uts; struct hostent *he; struct RTP *rtp; FILE *fp; unsigned int tr,tr_last=-1,tr_wrap,tr_diff,tr_long; unsigned short seq; unsigned int timestamp,ssrc; struct timeval start,now; int delay; /* build cname */ user = getenv("USER"); if (NULL == user) user = getenv("LOGNAME"); uname(&uts); he = gethostbyname(uts.nodename); sdes[1] = malloc(256); sprintf(sdes[1],"%s@%s",user,inet_ntoa(*(struct in_addr *) he->h_addr)); strcpy(my_addr,inet_ntoa(*(struct in_addr *) he->h_addr)); sdes[6] = name; /* parse options */ for (;;) { if (-1 == (c = getopt(argc, argv, "hf:s:a:p:i:"))) break; switch (c) { case 'f': filename = strdup(optarg); break; case 'i': strcpy(my_addr,optarg); break; case 'a': strcpy(dest_addr,optarg); break; case 'p': dest_port = atoi(optarg); break; case 's': send_psize = atoi(optarg); break; case 'h': default: usage(argv[0]); exit(1); } } /* h263 stream file */ if (filename) { if (NULL == (fp = fopen(filename,"rb"))) { perror(filename); exit(1); } } else { fp = stdin; if (isatty(0)) { usage(argv[0]); exit(1); } } signal(SIGINT,catch_signal); signal(SIGHUP,catch_signal); signal(SIGTERM,catch_signal); /* network stuff */ addr.sin_family = AF_INET; string_to_ipaddr(my_addr,&addr); dest.sin_family = AF_INET; dest.sin_port = htons (dest_port); string_to_ipaddr(dest_addr,&dest); retry_bind: if (-1 == s_rtcp) close(s_rtcp); if (-1 == s_rtp) close(s_rtp); my_port += 2; addr.sin_port = htons (my_port); /* rtcp socket */ if (-1 == (s_rtcp = socket (PF_INET, SOCK_DGRAM, 0))) { perror("socket rtcp"); exit(1); } if (-1 == bind(s_rtcp, (struct sockaddr*) &addr, sizeof(addr))) { if (errno == EADDRINUSE) goto retry_bind; perror("bind rtcp"); exit(1); } /* rtp socket */ addr.sin_port = htons (my_port-1); if (-1 == (s_rtp = socket (PF_INET, SOCK_DGRAM, 0))) { perror("socket rtp"); exit(1); } if (-1 == bind(s_rtp, (struct sockaddr*) &addr, sizeof(addr))) { if (errno == EADDRINUSE) goto retry_bind; perror("bind rtp"); exit(1); } packet = malloc(MAX_PACKET_SIZE); rtp = (struct RTP*)packet; srand(time(NULL)); seq = rand(); timestamp = rand(); ssrc = rand(); tr_last = 0; tr_wrap = 0; gettimeofday(&start,NULL); length = build_rtcp(packet, RTCP_TYPE_SR, ssrc,timestamp); length += build_rtcp(packet+length,RTCP_TYPE_SDES,ssrc,timestamp); dest.sin_port = htons (dest_port); if (-1 == (sendto(s_rtcp,packet,length,0, (struct sockaddr*)&dest,sizeof(dest)))) { perror("sendto"); exit(1); } /* main loop */ buffer = malloc(MAX_PACKET_SIZE); send_psize -= 14; /* RTP + Payload */ i = 0; buffer[i++] = fgetc(fp); buffer[i++] = fgetc(fp); buffer[i++] = fgetc(fp); for (;!stop;) { for (;;) { c = fgetc(fp); if (c == EOF) { printf("eof "); i += 3; break; } buffer[i++] = c; if (buffer[i-3] == 0 && buffer[i-2] == 0 && (buffer[i-1] & 0xfc) == 0x80) { printf("psc "); break; } } fflush(stdout); /* fwrite(buffer,1,i-3,out); */ /* send out frame -- one packet for now */ tr = ((buffer[2] & 0x03) << 6) | ((buffer[3] & 0xfc) >> 2); if (tr < tr_last) { tr_diff = tr+256-tr_last, tr_wrap++; /* send one RTCP packet */ length = build_rtcp(packet, RTCP_TYPE_SR, ssrc,timestamp); length += build_rtcp(packet+length,RTCP_TYPE_SDES,ssrc,timestamp); dest.sin_port = htons (dest_port); if (-1 == (sendto(s_rtcp,packet,length,0, (struct sockaddr*)&dest,sizeof(dest)))) { perror("sendto"); exit(1); } } else tr_diff = tr-tr_last; tr_long = tr_wrap*256+tr; timestamp += tr_diff * 3000; /* tr is 30Hz, timestamp 90kHz */ if (0 == tr_diff) timestamp++; tr_last = tr; gettimeofday(&now,NULL); delay = tr_long * 1000 / 30; delay -= (now.tv_sec - start.tv_sec)*1000; delay -= (now.tv_usec - start.tv_usec)/1000; if (delay > 0) usleep(delay*1000); if (stop) break; printf("tr=%3d/%4d, len=%4d ",tr,tr_long,i-3); #if 0 dump_paket(buffer,16); #endif rtp->flags = 0x80; rtp->pt = 42 /* payload type */; rtp->timestamp = htonl(timestamp); rtp->ssrc = ssrc; dest.sin_port = htons (dest_port-1); for (n = 2; n < i-3; n += ps) { rtp->payload[0] = 0; if (2 == n) rtp->payload[0] |= htonl(0x04000000); /* set P bit */ ps = (i-3) - n; if (ps > send_psize) { if (ps > send_psize + 64) ps = send_psize; else ps = send_psize-64; } else rtp->pt |= 0x80; /* set M bit */ rtp->seq = htons(seq++); memcpy(((char*)(&(rtp->payload[0])))+2,&buffer[n],ps); if (-1 == (sendto(s_rtp,packet,ps+14,0, (struct sockaddr*)&dest,sizeof(dest)))) { perror("sendto"); exit(1); } printf("*"); paket_count++; octet_count += ps+14; } printf("\n"); if (c == EOF) break; buffer[0] = buffer[i-3]; buffer[1] = buffer[i-2]; buffer[2] = buffer[i-1]; i = 3; } fclose(fp); sleep(1); length = build_rtcp(packet, RTCP_TYPE_BYE, ssrc,timestamp); dest.sin_port = htons (dest_port); if (-1 == (sendto(s_rtcp,packet,length,0, (struct sockaddr*)&dest,sizeof(dest)))) { perror("sendto"); exit(1); } /* keep compiler happy */ return 0; }