4 * Copyright (C) Alban Bedel - 04/2003
6 * This file is part of MPlayer, a free movie player.
8 * MPlayer is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
13 * MPlayer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with MPlayer; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
42 #include "stream/stream.h"
43 #include "libmpdemux/demuxer.h"
45 #include "libavutil/common.h"
48 /// Netstream packets def and some helpers
49 #include "stream/netstream.h"
52 //Set some standard variables
53 char* dvdsub_lang
=NULL
;
54 char* audio_lang
=NULL
;
67 static unsigned short int port
= 10000;
69 typedef struct client_st client_t
;
77 static int write_error(int fd
,char* msg
) {
78 int len
= strlen(msg
) + 1;
79 return write_packet(fd
,NET_STREAM_ERROR
,msg
,len
);
82 static int net_stream_open(client_t
* cl
,char* url
) {
83 int file_format
=DEMUXER_TYPE_UNKNOWN
;
84 mp_net_stream_opened_t ret
;
87 if(!write_error(cl
->fd
,"A stream is currently opened\n"))
92 mp_msg(MSGT_NETST
,MSGL_V
,"Open stream %s\n",url
);
93 cl
->stream
= open_stream(url
,NULL
,&file_format
);
95 if(!write_error(cl
->fd
,"Open failed\n"))
99 stream_reset(cl
->stream
);
100 stream_seek(cl
->stream
,cl
->stream
->start_pos
);
101 ret
.file_format
= file_format
;
102 ret
.flags
= cl
->stream
->flags
;
103 ret
.sector_size
= cl
->stream
->sector_size
;
104 ret
.start_pos
= cl
->stream
->start_pos
;
105 ret
.end_pos
= cl
->stream
->end_pos
;
106 net_stream_opened_2_me(&ret
);
108 if(!write_packet(cl
->fd
,NET_STREAM_OK
,(char*)&ret
,sizeof(mp_net_stream_opened_t
)))
113 static int net_stream_fill_buffer(client_t
* cl
,uint16_t max_len
) {
115 mp_net_stream_packet_t
*pack
;
118 if(!write_error(cl
->fd
,"No stream is currently opened\n"))
123 if(!write_error(cl
->fd
,"Fill buffer called with 0 length\n"))
127 pack
= malloc(max_len
+ sizeof(mp_net_stream_packet_t
));
128 pack
->cmd
= NET_STREAM_OK
;
129 r
= stream_read(cl
->stream
,pack
->data
,max_len
);
130 pack
->len
= le2me_16(r
+ sizeof(mp_net_stream_packet_t
));
131 if(!net_write(cl
->fd
,(char*)pack
,le2me_16(pack
->len
))) {
139 static int net_stream_seek(client_t
* cl
, uint64_t pos
) {
142 if(!write_error(cl
->fd
,"No stream is currently opened\n"))
147 if(!stream_seek(cl
->stream
,(off_t
)pos
)) {
148 if(!write_error(cl
->fd
,"Seek failed\n"))
152 if(!write_packet(cl
->fd
,NET_STREAM_OK
,NULL
,0))
157 static int net_stream_reset(client_t
* cl
) {
159 if(!write_error(cl
->fd
,"No stream is currently opened\n"))
163 stream_reset(cl
->stream
);
164 if(!write_packet(cl
->fd
,NET_STREAM_OK
,NULL
,0))
169 static int net_stream_close(client_t
* cl
) {
171 if(!write_error(cl
->fd
,"No stream is currently opened\n"))
176 free_stream(cl
->stream
);
179 if(!write_packet(cl
->fd
,NET_STREAM_OK
,NULL
,0))
184 int handle_client(client_t
* cl
,mp_net_stream_packet_t
* pack
) {
190 case NET_STREAM_OPEN
:
191 if(((char*)pack
)[pack
->len
-1] != '\0') {
192 mp_msg(MSGT_NETST
,MSGL_WARN
,"Got invalid open packet\n");
195 return net_stream_open(cl
,pack
->data
);
196 case NET_STREAM_FILL_BUFFER
:
197 if(pack
->len
!= sizeof(mp_net_stream_packet_t
) + 2) {
198 mp_msg(MSGT_NETST
,MSGL_WARN
,"Got invalid fill buffer packet\n");
201 return net_stream_fill_buffer(cl
,le2me_16(*((uint16_t*)pack
->data
)));
202 case NET_STREAM_SEEK
:
203 if(pack
->len
!= sizeof(mp_net_stream_packet_t
) + 8) {
204 mp_msg(MSGT_NETST
,MSGL_WARN
,"Got invalid fill buffer packet\n");
207 return net_stream_seek(cl
,le2me_64(*((uint64_t*)pack
->data
)));
208 case NET_STREAM_RESET
:
209 return net_stream_reset(cl
);
210 case NET_STREAM_CLOSE
:
211 if(pack
->len
!= sizeof(mp_net_stream_packet_t
)){
212 mp_msg(MSGT_NETST
,MSGL_WARN
,"Got invalid fill buffer packet\n");
215 return net_stream_close(cl
);
217 mp_msg(MSGT_NETST
,MSGL_WARN
,"Got unknown command %d\n",pack
->cmd
);
218 if(!write_error(cl
->fd
,"Unknown command\n"))
224 static client_t
* add_client(client_t
*head
,int fd
) {
225 client_t
*new = calloc(1,sizeof(client_t
));
227 if(!head
) return new;
233 static int make_fd_set(fd_set
* fds
, client_t
** _cl
, int listen
) {
239 // Remove this client
242 if(cl
->prev
) cl
->prev
->next
= cl
->next
;
243 if(cl
->next
) cl
->next
->prev
= cl
->prev
;
244 if(cl
->stream
) free_stream(cl
->stream
);
245 if(!cl
->prev
) // Remove the head
252 if(cl
->fd
> max_fd
) max_fd
= cl
->fd
;
258 /// Hack to 'cleanly' exit
259 static int run_server
= 1;
261 void exit_sig(int sig
) {
262 static int count
= 0;
263 sig
++; // gcc warning
265 if(count
==3) exit(1);
270 kill(getpid(),SIGKILL
);
275 static int main_loop(int listen_fd
) {
276 client_t
*clients
= NULL
,*iter
;
279 signal(SIGTERM
,exit_sig
); // kill
281 signal(SIGHUP
,exit_sig
); // kill -HUP / xterm closed
282 signal(SIGINT
,exit_sig
); // Interrupt from keyboard
283 signal(SIGQUIT
,exit_sig
); // Quit from keyboard
287 int sel_n
= make_fd_set(&fds
,&clients
,listen_fd
);
288 int n
= select(sel_n
,&fds
,NULL
,NULL
,NULL
);
292 mp_msg(MSGT_NETST
,MSGL_FATAL
,"Select error: %s\n",strerror(errno
));
296 if(FD_ISSET(listen_fd
,&fds
)) {
297 struct sockaddr_in addr
;
298 socklen_t slen
= sizeof(struct sockaddr_in
);
299 int client_fd
= accept(listen_fd
,(struct sockaddr
*)&addr
,&slen
);
301 mp_msg(MSGT_NETST
,MSGL_ERR
,"accept failed: %s\n",strerror(errno
));
304 mp_msg(MSGT_NETST
,MSGL_V
,"New client from %s\n",inet_ntoa(addr
.sin_addr
));
305 clients
= add_client(clients
,client_fd
);
308 // Look for the clients
309 for(iter
= clients
; iter
; iter
= iter
->next
) {
310 mp_net_stream_packet_t
* pack
;
311 if(!FD_ISSET(iter
->fd
,&fds
)) continue;
312 pack
= read_packet(iter
->fd
);
318 if(!handle_client(iter
,pack
)) {
325 mp_msg(MSGT_NETST
,MSGL_INFO
,"Exit ....\n");
331 client_t
* f
= clients
;
332 if(f
->stream
) free_stream(f
->stream
);
333 if(f
->fd
> 0) close(f
->fd
);
335 clients
= clients
->next
;
342 struct sockaddr_in addr
;
345 // mp_msg_set_level(verbose+MSGL_STATUS);
349 WSAStartup(MAKEWORD(1,1), &wsaData
);
351 listen_fd
= socket(AF_INET
, SOCK_STREAM
, 0);
353 mp_msg(MSGT_NETST
,MSGL_FATAL
,"Failed to create listen_fd: %s\n",strerror(errno
));
356 memset(&addr
,0,sizeof(struct sockaddr
));
357 addr
.sin_addr
.s_addr
= INADDR_ANY
;
358 addr
.sin_port
= htons(port
);
359 addr
.sin_family
= AF_INET
;
360 if(bind(listen_fd
,(struct sockaddr
*)&addr
,sizeof(struct sockaddr
))) {
361 mp_msg(MSGT_NETST
,MSGL_FATAL
,"Failed to bind listen socket: %s\n",strerror(errno
));
366 if(listen(listen_fd
,1)) {
367 mp_msg(MSGT_NETST
,MSGL_FATAL
,"Failed to turn the socket in listen state: %s\n",strerror(errno
));
370 return main_loop(listen_fd
);
375 //---- For libmpdemux
377 float stream_cache_seek_min_percent
=50.0;
378 float stream_cache_min_percent
=20.0;
380 #include <libmpdemux/demuxer.h>
381 #include <libmpdemux/stheader.h>
383 // audio stream skip/resync functions requires only for seeking.
384 // (they should be implemented in the audio codec layer)
385 void skip_audio_frame(sh_audio_t
*sh_audio
){
388 void resync_audio_stream(sh_audio_t
*sh_audio
){
392 int mp_input_check_interrupt(int time
){
393 if(time
) usleep(time
);
398 #include "get_path.c"
401 int stream_cache_size
=0;
406 int vo_osd_changed(int new_value
){ new_value
++; return 0;}
411 int suboverlap_enabled
= 1;