changeset 9856:08496327b7ec

A simple netstream server.
author albeu
date Sun, 06 Apr 2003 16:39:16 +0000
parents 15fe3fba5b1d
children 89b48bc6c441
files TOOLS/netstream/Makefile TOOLS/netstream/netstream.c
diffstat 2 files changed, 412 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TOOLS/netstream/Makefile	Sun Apr 06 16:39:16 2003 +0000
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TOOLS/netstream/netstream.c	Sun Apr 06 16:39:16 2003 +0000
@@ -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;
+
+//---------------