[xiph-commits] r9292 - trunk/xiph-rtp
giles at motherfish-iii.xiph.org
giles at motherfish-iii.xiph.org
Wed May 18 17:20:29 PDT 2005
Author: giles
Date: 2005-05-18 17:20:28 -0700 (Wed, 18 May 2005)
New Revision: 9292
Added:
trunk/xiph-rtp/theorartp-client.c
Log:
Fork the experimental vorbis rtp client for theora experiments.
Copied: trunk/xiph-rtp/theorartp-client.c (from rev 9291, trunk/xiph-rtp/vorbisrtp-client.c)
===================================================================
--- trunk/xiph-rtp/vorbisrtp-client.c 2005-05-18 14:46:00 UTC (rev 9291)
+++ trunk/xiph-rtp/theorartp-client.c 2005-05-19 00:20:28 UTC (rev 9292)
@@ -0,0 +1,320 @@
+/* Copyright (C) 2005 Xiph.org Foundation
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* sample RTP Theora client */
+
+/* compile with: gcc -g -O2 -Wall -o theorartp-client theorartp-client.c */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ogg/ogg.h>
+
+#define MAX_PACKET 1500
+
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+
+int dump_packet_raw(unsigned char *data, const int len, FILE *out)
+{
+ int i, j, n;
+
+ i = 0;
+ while (i < len) {
+ fprintf(out, " %04x ", i);
+ n = MIN(8, len - i);
+ for (j = 0; j < n; j++)
+ fprintf(out, " %02x", data[i+j]);
+ fprintf(out, " ");
+ n = MIN(16, len - i);
+ for (j = 8; j < 16; j++)
+ fprintf(out, " %02x", data[i+j]);
+ fprintf(out, " ");
+ for (j = 0; j < n; j++)
+ fprintf(out, "%c", isprint(data[i+j]) ? data[i+j] : '.');
+ fprintf(out, "\n");
+ i += 16;
+ }
+
+ return 0;
+}
+
+typedef struct _rtp_header {
+ int V,P,X,CC,M,PT;
+ unsigned short sequence;
+ unsigned int timestamp, ssrc;
+ unsigned int ident;
+ unsigned int csrc[16];
+ int offset;
+ const unsigned char *data, *payload;
+ int len, plen;
+} rtp_header;
+
+int parse_packet_rtp_header(const unsigned char *data,
+ const int len, rtp_header *rtp)
+{
+ int i;
+
+ /* check for bad arguments */
+ if ((data == NULL) || (rtp == NULL)|| (len < 12))
+ return -1;
+
+ /* parse RTP header */
+ rtp->V = (data[0] & 0xc0) >> 6; /* version */
+ rtp->P = (data[0] & 0x40) >> 5;
+ rtp->X = (data[0] & 0x20) >> 4;
+ rtp->CC = (data[0] & 0x0f); /* CSRC count */
+ rtp->M = (data[1] & 0x80) >> 7;
+ rtp->PT = (data[1] & 0x7F); /* packet type */
+ rtp->sequence = ntohs(((unsigned short *)data)[1]);
+ rtp->timestamp = ntohl(((unsigned int *)data)[1]);
+ rtp->ssrc = ntohl(((unsigned int *)data)[2]);
+ rtp->offset = (3 + rtp->CC) * 4; /* offset to payload header */
+
+ /* check space for the CSRC fields */
+ if (rtp->offset >= len) return -2;
+
+ /* read the CSRC list, and null empty entries */
+ for (i = 0; i < rtp->CC; i++)
+ rtp->csrc[i] = ntohl(((unsigned int *)data)[3+i]);
+ for (i = rtp->CC; i < 16; i++)
+ rtp->csrc[i] = 0;
+
+ /* index into the packet */
+ rtp->data = data;
+ rtp->len = len;
+ rtp->payload = data + rtp->offset;
+ rtp->plen = len - rtp->offset;
+
+ return 0; /* success */
+}
+
+int dump_packet_rtp_header(rtp_header *rtp, FILE *out)
+{
+ int i;
+
+ fprintf(out, "RTP packet V:%d P:%d X:%d M:%d PT:%d",
+ rtp->V, rtp->P, rtp->X, rtp->M, rtp->PT);
+ fprintf(out, " seq %d", rtp->sequence);
+ fprintf(out, " timestamp: %u\n", rtp->timestamp);
+ fprintf(out, " ssrc: 0x%08x\n", rtp->ssrc);
+ if (rtp->CC)
+ for (i = 0; i < rtp->CC; i++)
+ fprintf(out, " csrc: 0x%08x\n", rtp->csrc[i]);
+ else
+ fprintf(out, " no csrc\n");
+
+ return 0;
+}
+
+int dump_packet_rtp_vorbis(rtp_header *rtp, FILE *out)
+{
+ const unsigned char *payload = rtp->payload;
+ unsigned int ident;
+ int C,F,R,pkts;
+ int offset, length;
+ int i;
+
+ /* parse Vorbis payload header */
+ offset = rtp->offset;
+ ident = ntohl(*(unsigned int *)payload);
+ offset += 4;
+ C = (payload[offset] & 0x80) >> 7;
+ F = (payload[offset] & 0x40) >> 6;
+ R = (payload[offset] & 0x20) >> 5;
+ pkts = (payload[offset] & 0x1F);
+ offset++;
+
+ fprintf(out, " Vorbis payload ident 0x%08x C:%d F:%d R:%d",
+ ident, C, F, R);
+ fprintf(out, " packets:");
+ if (C == 0 && F == 0)
+ fprintf(out, " %d\n", pkts);
+ else if (C == 0 && F == 1)
+ fprintf(out, " frag start\n");
+ else if (C == 1 && F == 0)
+ fprintf(out, " frag cont.\n");
+ else /* C == 1 && F == 1 */
+ fprintf(out, " frag end\n");
+
+ for (i = 0; i < pkts; i++) {
+ if (offset >= rtp->plen) {
+ fprintf(stderr, "payload length overflow. corrupt packet?\n");
+ return -1;
+ }
+ length = payload[offset++];
+ fprintf(out, " data: %d bytes in block %d\n", length, i);
+ offset += length;
+ }
+ if (pkts == 0) {
+ length = payload[offset++];
+ fprintf(out, " data: %d bytes in fragment\n", length);
+ offset += length;
+ }
+
+ if (rtp->plen - offset > 0)
+ fprintf(out, " %d unused bytes at the end of the packet!\n",
+ rtp->plen - offset);
+
+ return 0;
+}
+
+int dump_packet_rtp_theora(rtp_header *rtp, FILE *out)
+{
+ const unsigned char *payload = rtp->payload;
+ unsigned int ident;
+ int C,F,R,pkts;
+ int offset, length;
+ int i;
+
+ /* parse Theora payload header */
+ offset = rtp->offset;
+ ident = ntohl(*(unsigned int *)payload);
+ offset += 4;
+ C = (payload[offset] & 0x80) >> 7;
+ F = (payload[offset] & 0x40) >> 6;
+ R = (payload[offset] & 0x20) >> 5;
+ pkts = (payload[offset] & 0x1F);
+ offset++;
+
+ fprintf(out, " Theora payload ident 0x%08x C:%d F:%d R:%d",
+ ident, C, F, R);
+ fprintf(out, " packets:");
+ if (C == 0 && F == 0)
+ fprintf(out, " %d\n", pkts);
+ else if (C == 0 && F == 1)
+ fprintf(out, " frag start\n");
+ else if (C == 1 && F == 0)
+ fprintf(out, " frag cont.\n");
+ else /* C == 1 && F == 1 */
+ fprintf(out, " frag end\n");
+
+ return 0;
+}
+
+int dump_packet_rtp_unknown(rtp_header *rtp, FILE *out)
+{
+ fprintf(out, " Unknown packet type\n");
+
+ return 0;
+}
+
+int dump_packet_rtp(const unsigned char *data, const int len, FILE *out)
+{
+ rtp_header rtp;
+
+ parse_packet_rtp_header(data, len, &rtp);
+ dump_packet_rtp_header(&rtp, out);
+
+ switch (rtp.PT) {
+ case 96: /* vorbis */
+ dump_packet_rtp_vorbis(&rtp, out);
+ break;
+ case 98: /* theora */
+ dump_packet_rtp_theora(&rtp, out);
+ break;
+ default:
+ dump_packet_rtp_unknown(&rtp, out);
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int RTPSocket, ret;
+ int optval = 0;
+ struct sockaddr_in us, them;
+ struct ip_mreq group;
+ unsigned char data[MAX_PACKET];
+ char *hostname;
+ unsigned int port;
+
+ if (argc < 2) hostname = "227.0.0.1";
+ else hostname = argv[1];
+
+ if (argc < 3) port = 4045;
+ else port = atoi(argv[2]);
+
+ fprintf(stderr, "Opening connection to %s port %d\n", hostname, port);
+
+ RTPSocket = socket(AF_INET, SOCK_DGRAM, 0);
+
+ if (RTPSocket < 0) {
+ fprintf(stderr, "Unable to create socket.\n");
+ exit(1);
+ }
+
+ us.sin_family = AF_INET;
+ us.sin_addr.s_addr = htonl(INADDR_ANY);
+ us.sin_port = htons(port);
+ ret = bind(RTPSocket, (struct sockaddr *)&us, sizeof(us));
+ if (ret < 0) {
+ fprintf(stderr, "Unable to bind socket!\n");
+ exit(1);
+ }
+
+ them.sin_family = AF_INET;
+ them.sin_addr.s_addr = inet_addr(hostname);
+ them.sin_port = htons(port);
+
+ if (!IN_MULTICAST(ntohl(them.sin_addr.s_addr))) {
+ fprintf(stderr, "not a multicast address\n");
+ } else {
+ fprintf(stderr, "joining multicast group...\n");
+ group.imr_multiaddr.s_addr = them.sin_addr.s_addr;
+ group.imr_interface.s_addr = htonl(INADDR_ANY);
+ ret = setsockopt(RTPSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (void *)&group, sizeof(group));
+ if (ret < 0) {
+ fprintf(stderr, "cannot join multicast group!\n");
+ exit(1);
+ }
+ }
+
+ while (1) {
+ ret = recvfrom(RTPSocket, data, MAX_PACKET, 0, NULL, 0);
+ fprintf(stderr, "read %d bytes of data\n", ret);
+ dump_packet_rtp(data, ret, stdout);
+ dump_packet_raw(data, ret, stdout);
+ }
+
+ return 0;
+}
More information about the commits
mailing list