From 5c2e3e4489486a30d8f14338277de093b4d94cf0 Mon Sep 17 00:00:00 2001 From: michael Date: Sat, 1 Jul 2006 17:02:54 +0000 Subject: [PATCH] record a stream (for example from getstream) --- .cvsignore | 2 ++ Makefile | 19 +++++++++++ common.c | 64 ++++++++++++++++++++++++++++++++++++ common.h | 7 ++++ http.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ http.h | 2 ++ mcast.c | 23 +++++++++++++ mcast.h | 2 ++ record-dvb.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 296 insertions(+) create mode 100644 .cvsignore create mode 100644 Makefile create mode 100644 common.c create mode 100644 common.h create mode 100644 http.c create mode 100644 http.h create mode 100644 mcast.c create mode 100644 mcast.h create mode 100644 record-dvb.c diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..5a75ec1 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,2 @@ +record-dvb +*.d diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f3306ce --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +CFLAGS =-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -Wall -g + +OBJS = record-dvb.o http.o mcast.o common.o + +all: record-dvb + +DEPEND=$(OBJS:.o=.d) +-include $(DEPEND) + +record-dvb: $(OBJS) + +clean: + rm -f record-dvb $(OBJS) $(DEPEND) + +%.o: %.c + $(COMPILE.c) $(OUTPUT_OPTION) $< + $(COMPILE.c) -MM $< > $*.d + +.PHONY: all clean diff --git a/common.c b/common.c new file mode 100644 index 0000000..97ec807 --- /dev/null +++ b/common.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +#include "common.h" + +struct dvb_host *parse(char *urlpart, char *defport) +{ + struct dvb_host *dvbhost; + char *pos; + + if (!(dvbhost = malloc(sizeof(struct dvb_host)))) { + perror("malloc"); + exit(EXIT_FAILURE); + } + + bzero(dvbhost, sizeof(struct dvb_host)); + + if (!(dvbhost->hostname = strdup(urlpart))) { + perror("strdup"); + exit(EXIT_FAILURE); + } + + /* Unneded, but better readablity: */ + dvbhost->location = NULL; + dvbhost->port = NULL; + + pos = dvbhost->hostname; + + while(*pos != '\0' && *pos != ':' && *pos != '/') + pos++; + + if (*pos == '/') + dvbhost->location = pos + 1; + + if (*pos == ':') + dvbhost->port = pos + 1; + + *pos = 0; + + if (dvbhost->port) { + pos++; + + while(*pos != '\0' && *pos != '/') + pos ++; + + if(*pos == '/') + dvbhost->location = pos + 1; + + *pos = 0; + } + + if (!dvbhost->port) + dvbhost->port = strdup(defport); + + if (!dvbhost->location) + if(!(dvbhost->location = strdup(""))) { + perror("strdup"); + exit(EXIT_FAILURE); + } + + return dvbhost; +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..5f7b1f8 --- /dev/null +++ b/common.h @@ -0,0 +1,7 @@ +struct dvb_host { + char *hostname; + char *port; + char *location; +}; + +struct dvb_host *parse(char *urlpart, char *defport); diff --git a/http.c b/http.c new file mode 100644 index 0000000..a4f4c91 --- /dev/null +++ b/http.c @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "http.h" + +#define BUFFSIZE 1024 + +int is_http(char *url) +{ + if (strlen(url) < 8) + return 0; + + if (!strncasecmp("http://",url,7)) + return 1; + + return 0; +} + +int open_http(char *url) +{ + int fd; + struct sockaddr_in server; + struct dvb_host *dvbhost; + struct addrinfo *s_addrinfo, addrhints; + char buffer[BUFFSIZE]; + int i; + + if(!is_http(url)) + return -1; + + dvbhost = parse(&(url[7]), "80"); + + bzero(&addrhints, sizeof(struct addrinfo)); + addrhints.ai_family = PF_INET; + addrhints.ai_socktype = SOCK_STREAM; + + if ((i=getaddrinfo(dvbhost->hostname, dvbhost->port, &addrhints, &s_addrinfo))) { + fprintf(stderr,"getaddrinfo: %s\n",gai_strerror(i)); + return -1; + } + + if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + perror("socket"); + return -1; + } + + bzero(&server, sizeof(struct sockaddr_in)); + server.sin_family = AF_INET; + server.sin_addr.s_addr = ((struct sockaddr_in*)(s_addrinfo->ai_addr))->sin_addr.s_addr; + server.sin_port = ((struct sockaddr_in*)(s_addrinfo->ai_addr))->sin_port; + + if (connect(fd, (struct sockaddr*) &server, sizeof(server)) < 0) { + perror("connect"); + return -1; + } + + freeaddrinfo(s_addrinfo); + + + snprintf(buffer, BUFFSIZE-1, "GET /%s HTTP/1.0\n\n",dvbhost->location); + buffer[BUFFSIZE-1] = 0; + send(fd, buffer, strlen(buffer), 0); + i = 0; + while(i < 2) { + if (recv(fd, buffer, 1, 0) < 1) { + perror("recv"); + exit(EXIT_FAILURE); + } + printf("%c",buffer[0]); + if (buffer[0] == 0x0a) + i++; + else + if (buffer[0] != 0x0d) + i = 0; + } + + return fd; +} diff --git a/http.h b/http.h new file mode 100644 index 0000000..f5f5cb1 --- /dev/null +++ b/http.h @@ -0,0 +1,2 @@ +int is_http(char *url); +int open_http(char *url); diff --git a/mcast.c b/mcast.c new file mode 100644 index 0000000..a8be22f --- /dev/null +++ b/mcast.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include "mcast.h" + +int is_mcast(char *url) +{ + if (strlen(url) < 7) + return 0; + + if (!strncasecmp("udp://",url,6)) + return 1; + + return 0; +} + +int open_mcast(char *url) +{ + fprintf(stderr,"multicast currently unimplemented!\n"); + + exit(EXIT_FAILURE); +} diff --git a/mcast.h b/mcast.h new file mode 100644 index 0000000..e60cc90 --- /dev/null +++ b/mcast.h @@ -0,0 +1,2 @@ +int is_mcast(char *url); +int open_mcast(char *url); diff --git a/record-dvb.c b/record-dvb.c new file mode 100644 index 0000000..aa48bb4 --- /dev/null +++ b/record-dvb.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "http.h" +#include "mcast.h" + +#define CHUNKSIZE 8192 + +void record(int(*open_fn)(char *), char *url, char *outfile, int duration) +{ + struct timeval start, curr; + int bytes, written; + char buffer[CHUNKSIZE]; + int i; + int in, out; + + if ((out = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_LARGEFILE, 00644)) < 0) { + perror("open"); + exit(EXIT_FAILURE); + } + + if ((in = (*open_fn)(url)) < 0) { + fprintf(stderr,"Can't open url %s!\n",url); + exit(EXIT_FAILURE); + } + + printf("Recording from %s for %d seconds...\n", url, duration); + + gettimeofday(&start, NULL); + + do { + if ((bytes = recv(in, buffer, CHUNKSIZE, 0)) < 1) { + perror("recv"); + exit(EXIT_FAILURE); + } + + written = 0; + do { + if ((i = write(out, buffer, bytes-written)) < 0) { + perror("write"); + exit(EXIT_FAILURE); + } + written += i; + } while(written < bytes); + + gettimeofday(&curr, NULL); + } while (curr.tv_sec < start.tv_sec+duration); + + close(out); + close(in); + shutdown(in, SHUT_RDWR); +} + +int main(int argc, char **argv) +{ + int duration; + char *url; + char *outfile; + int(*open_fn)(char *); + + if (argc == 4) { + url = argv[1]; + duration = atol(argv[2])*60; + outfile = argv[3]; + } else { + fprintf(stderr,"Syntax: %s URL duration outfile\n", argv[0]); + exit(EXIT_FAILURE); + } + + if (is_http(url)) { + open_fn = &open_http; + } else if (is_mcast(url)) { + open_fn = &open_mcast; + } else { + printf("URL %s not supported!\n", url); + exit(EXIT_FAILURE); + } + + record(open_fn, url, outfile, duration); + + return EXIT_SUCCESS; +} -- 2.39.2