summaryrefslogtreecommitdiffstats
path: root/TOOLS
diff options
context:
space:
mode:
authoralbeu <albeu@b3059339-0415-0410-9bf9-f77b7e298cf2>2003-04-06 16:39:16 +0000
committeralbeu <albeu@b3059339-0415-0410-9bf9-f77b7e298cf2>2003-04-06 16:39:16 +0000
commit4ffd483b4832126e6155ac3174a7d4a939e455e2 (patch)
tree24d823735f3d2264f308f6656fbf6b0510f46c37 /TOOLS
parentdf67e3e8e27123969edae04f5e7182f8ec2b5ca3 (diff)
downloadmpv-4ffd483b4832126e6155ac3174a7d4a939e455e2.tar.bz2
mpv-4ffd483b4832126e6155ac3174a7d4a939e455e2.tar.xz
A simple netstream server.
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@9857 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'TOOLS')
-rw-r--r--TOOLS/netstream/Makefile38
-rw-r--r--TOOLS/netstream/netstream.c374
2 files changed, 412 insertions, 0 deletions
diff --git a/TOOLS/netstream/Makefile b/TOOLS/netstream/Makefile
new file mode 100644
index 0000000000..e8b1bac200
--- /dev/null
+++ b/TOOLS/netstream/Makefile
@@ -0,0 +1,38 @@
+
+MPROOT=../..
+
+include $(MPROOT)/config.mak
+
+INCLUDE = -I$(MPROOT) -I$(MPROOT)/loader $(EXTRA_INC)
+CFLAGS = $(OPTFLAGS) $(INCLUDE)
+
+.SUFFIXES: .c .cpp .o
+
+# .PHONY: all clean
+
+all: netstream
+
+.c.o:
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+
+netstream: $(MPROOT)/libmpdemux/libmpdemux.a netstream.o
+ $(CC) $(CFLAGS) -g netstream.o $(MPROOT)/mp_msg.c $(MPROOT)/osdep/shmem.c -o netstream $(MPROOT)/libmpdemux/libmpdemux.a $(MPROOT)/libmpdvdkit2/libmpdvdkit.a $(MPROOT)/libvo/aclib.o $(MPROOT)/libmpcodecs/img_format.o $(MPROOT)/libao2/afmt.o $(MPROOT)/sub_cc.o $(MPROOT)/m_option.o $(MPROOT)/m_struct.o $(MPROOT)/subreader.o $(ALSA_LIB) $(VORBIS_LIB) $(CDPARANOIA_LIB) -lz -lpthread
+
+clean:
+ rm -f *.o *.a *~
+
+distclean:
+ rm -f test Makefile.bak *.o *.a *~ .depend
+
+dep: depend
+
+depend:
+ $(CC) -MM $(CFLAGS) test.c $(SRCS) 1>.depend
+
+#
+# include dependency files if they exist
+#
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff --git a/TOOLS/netstream/netstream.c b/TOOLS/netstream/netstream.c
new file mode 100644
index 0000000000..6191f613d9
--- /dev/null
+++ b/TOOLS/netstream/netstream.c
@@ -0,0 +1,374 @@
+/*
+ * netstream.c
+ *
+ * Copyright (C) Alban Bedel - 04/2003
+ *
+ * This file is part of MPlayer, a free movie player.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Make; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <libmpdemux/stream.h>
+#include <mp_msg.h>
+
+/// Netstream packets def and some helpers
+#include <libmpdemux/netstream.h>
+
+static unsigned short int port = 10000;
+
+typedef struct client_st client_t;
+struct client_st {
+ int fd;
+ stream_t* stream;
+ client_t* next;
+ client_t* prev;
+};
+
+static int write_error(int fd,char* msg) {
+ int len = strlen(msg) + 1;
+ return write_packet(fd,NET_STREAM_ERROR,msg,len);
+}
+
+static int net_stream_open(client_t* cl,char* url) {
+ int file_format;
+ mp_net_stream_opened_t ret;
+
+ if(cl->stream) {
+ if(!write_error(cl->fd,"A stream is currently opened\n"))
+ return 0;
+ return 1;
+ }
+
+ mp_msg(MSGT_NETST,MSGL_V,"Open stream %s\n",url);
+ cl->stream = open_stream(url,NULL,&file_format);
+ if(!cl->stream) {
+ if(!write_error(cl->fd,"Open failed\n"))
+ return 0;
+ return 1;
+ }
+ stream_reset(cl->stream);
+ stream_seek(cl->stream,cl->stream->start_pos);
+ ret.file_format = file_format;
+ ret.flags = cl->stream->flags;
+ ret.sector_size = cl->stream->sector_size;
+ ret.start_pos = cl->stream->start_pos;
+ ret.end_pos = cl->stream->end_pos;
+
+ if(!write_packet(cl->fd,NET_STREAM_OK,(char*)&ret,sizeof(mp_net_stream_opened_t)))
+ return 0;
+ return 1;
+}
+
+static int net_stream_fill_buffer(client_t* cl,uint16_t max_len) {
+ int r;
+ mp_net_stream_packet_t *pack;
+
+ if(!cl->stream) {
+ if(!write_error(cl->fd,"No stream is currently opened\n"))
+ return 0;
+ return 1;
+ }
+ if(max_len == 0) {
+ if(!write_error(cl->fd,"Fill buffer called with 0 lenght\n"))
+ return 0;
+ return 1;
+ }
+ pack = malloc(max_len + sizeof(mp_net_stream_packet_t));
+ pack->cmd = NET_STREAM_OK;
+ r = stream_read(cl->stream,pack->data,max_len);
+ pack->len = r + sizeof(mp_net_stream_packet_t);
+ if(!net_write(cl->fd,(char*)pack,pack->len)) {
+ free(pack);
+ return 0;
+ }
+ free(pack);
+ return 1;
+}
+
+static int net_stream_seek(client_t* cl, uint64_t pos) {
+
+ if(!cl->stream) {
+ if(!write_error(cl->fd,"No stream is currently opened\n"))
+ return 0;
+ return 1;
+ }
+
+ if(!stream_seek(cl->stream,(off_t)pos)) {
+ if(!write_error(cl->fd,"Seek failed\n"))
+ return 0;
+ return 1;
+ }
+ if(!write_packet(cl->fd,NET_STREAM_OK,NULL,0))
+ return 0;
+ return 1;
+}
+
+static int net_stream_reset(client_t* cl) {
+ if(!cl->stream) {
+ if(!write_error(cl->fd,"No stream is currently opened\n"))
+ return 0;
+ return 1;
+ }
+ stream_reset(cl->stream);
+ if(!write_packet(cl->fd,NET_STREAM_OK,NULL,0))
+ return 0;
+ return 1;
+}
+
+static int net_stream_close(client_t* cl) {
+ if(!cl->stream) {
+ if(!write_error(cl->fd,"No stream is currently opened\n"))
+ return 0;
+ return 1;
+ }
+
+ free_stream(cl->stream);
+ cl->stream = NULL;
+
+ if(!write_packet(cl->fd,NET_STREAM_OK,NULL,0))
+ return 0;
+ return 1;
+}
+
+int handle_client(client_t* cl,mp_net_stream_packet_t* pack) {
+
+ if(!pack)
+ return 0;
+
+ switch(pack->cmd) {
+ case NET_STREAM_OPEN:
+ if(((char*)pack)[pack->len-1] != '\0') {
+ mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid open packet\n");
+ return 0;
+ }
+ return net_stream_open(cl,pack->data);
+ case NET_STREAM_FILL_BUFFER:
+ if(pack->len != sizeof(mp_net_stream_packet_t) + 2) {
+ mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid fill buffer packet\n");
+ return 0;
+ }
+ return net_stream_fill_buffer(cl,*((uint16_t*)pack->data));
+ case NET_STREAM_SEEK:
+ if(pack->len != sizeof(mp_net_stream_packet_t) + 8) {
+ mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid fill buffer packet\n");
+ return 0;
+ }
+ return net_stream_seek(cl,*((uint64_t*)pack->data));
+ case NET_STREAM_RESET:
+ return net_stream_reset(cl);
+ case NET_STREAM_CLOSE:
+ if(pack->len != sizeof(mp_net_stream_packet_t)){
+ mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid fill buffer packet\n");
+ return 0;
+ }
+ return net_stream_close(cl);
+ default:
+ mp_msg(MSGT_NETST,MSGL_WARN,"Got unknow command %d\n",pack->cmd);
+ if(!write_error(cl->fd,"Unknow command\n"))
+ return 0;
+ }
+ return 0;
+}
+
+static client_t* add_client(client_t *head,int fd) {
+ client_t *new = calloc(1,sizeof(client_t));
+ new->fd = fd;
+ if(!head) return new;
+ new->next = head;
+ head->prev = new;
+ return new;
+}
+
+static int make_fd_set(fd_set* fds, client_t** _cl, int listen) {
+ int max_fd = listen;
+ client_t *cl = *_cl;
+ FD_ZERO(fds);
+ FD_SET(listen,fds);
+ while(cl) {
+ // Remove this client
+ if(cl->fd < 0) {
+ client_t* f = cl;
+ if(cl->prev) cl->prev->next = cl->next;
+ if(cl->next) cl->next->prev = cl->prev;
+ if(cl->stream) free_stream(cl->stream);
+ if(!cl->prev) // Remove the head
+ *_cl = cl->next;
+ cl = cl->next;
+ free(f);
+ continue;
+ }
+ FD_SET(cl->fd,fds);
+ if(cl->fd > max_fd) max_fd = cl->fd;
+ cl = cl->next;
+ }
+ return max_fd+1;
+}
+
+/// Hack to 'cleanly' exit
+static int run_server = 1;
+
+void exit_sig(int sig) {
+ static int count = 0;
+ sig++; // gcc warning
+ count++;
+ if(count==3) exit(1);
+ if(count > 3)
+ kill(getpid(),SIGKILL);
+ run_server = 0;
+}
+
+static int main_loop(int listen_fd) {
+ client_t *clients = NULL,*iter;
+ fd_set fds;
+
+ signal(SIGTERM,exit_sig); // kill
+ signal(SIGHUP,exit_sig); // kill -HUP / xterm closed
+ signal(SIGINT,exit_sig); // Interrupt from keyboard
+ signal(SIGQUIT,exit_sig); // Quit from keyboard
+
+
+ while(run_server) {
+ int sel_n = make_fd_set(&fds,&clients,listen_fd);
+ int n = select(sel_n,&fds,NULL,NULL,NULL);
+ if(n < 0) {
+ if(errno == EINTR)
+ continue;
+ mp_msg(MSGT_NETST,MSGL_FATAL,"Select error: %s\n",strerror(errno));
+ return 1;
+ }
+ // New connection
+ if(FD_ISSET(listen_fd,&fds)) {
+ struct sockaddr_in addr;
+ socklen_t slen = sizeof(struct sockaddr_in);
+ int client_fd = accept(listen_fd,(struct sockaddr*)&addr,&slen);
+ if(client_fd < 0) {
+ mp_msg(MSGT_NETST,MSGL_ERR,"accept failed: %s\n",strerror(errno));
+ continue;
+ }
+ mp_msg(MSGT_NETST,MSGL_V,"New client from %s\n",inet_ntoa(addr.sin_addr));
+ clients = add_client(clients,client_fd);
+ if(n == 1) continue;
+ }
+ // Look for the clients
+ for(iter = clients ; iter ; iter = iter->next) {
+ mp_net_stream_packet_t* pack;
+ if(!FD_ISSET(iter->fd,&fds)) continue;
+ pack = read_packet(iter->fd);
+ if(!pack) {
+ close(iter->fd);
+ iter->fd = -1;
+ continue;
+ }
+ if(!handle_client(iter,pack)) {
+ close(iter->fd);
+ iter->fd = -1;
+ }
+ free(pack);
+ }
+ }
+ mp_msg(MSGT_NETST,MSGL_INFO,"Exit ....\n");
+ close(listen_fd);
+ while(clients) {
+ client_t* f = clients;
+ if(f->stream) free_stream(f->stream);
+ if(f->fd > 0) close(f->fd);
+ free(f);
+ clients = clients->next;
+ }
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ int listen_fd;
+ struct sockaddr_in addr;
+
+ mp_msg_init();
+ mp_msg_set_level(verbose+MSGL_STATUS);
+
+ listen_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if(listen_fd < 0) {
+ mp_msg(MSGT_NETST,MSGL_FATAL,"Failed to create listen_fd: %s\n",strerror(errno));
+ return -1;
+ }
+ memset(&addr,0,sizeof(struct sockaddr));
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_port = htons(port);
+ addr.sin_family = AF_INET;
+ if(bind(listen_fd,(struct sockaddr*)&addr,sizeof(struct sockaddr))) {
+ mp_msg(MSGT_NETST,MSGL_FATAL,"Failed to bind listen socket: %s\n",strerror(errno));
+ return -1;
+ }
+
+
+ if(listen(listen_fd,1)) {
+ mp_msg(MSGT_NETST,MSGL_FATAL,"Failed to turn the socket in listen state: %s\n",strerror(errno));
+ return -1;
+ }
+ return main_loop(listen_fd);
+}
+
+
+
+//---- For libmpdemux
+
+#include <libmpdemux/demuxer.h>
+#include <libmpdemux/stheader.h>
+
+// audio stream skip/resync functions requires only for seeking.
+// (they should be implemented in the audio codec layer)
+void skip_audio_frame(sh_audio_t *sh_audio){
+ sh_audio=NULL;
+}
+void resync_audio_stream(sh_audio_t *sh_audio){
+ sh_audio=NULL;
+}
+
+int mp_input_check_interrupt(int time){
+ if(time) usleep(time);
+ return 0;
+}
+
+// for libmpdvdkit2:
+#include "../get_path.c"
+
+int verbose=0;
+
+int stream_cache_size=0;
+
+// for demux_ogg:
+void* vo_sub=NULL;
+int vo_osd_changed(int new_value){ new_value++; return 0;}
+int subcc_enabled=0;
+
+float sub_fps=0;
+int sub_utf8=0;
+int suboverlap_enabled = 1;
+float sub_delay=0;
+
+//---------------