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 GNU Make; see the file COPYING. If not, write to
20 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26 * Net stream allow you to access MPlayer stream accross a tcp
28 * Note that at least mf and tv use a dummy stream (they are
29 * implemented at the demuxer level) so you won't be able to
30 * access those :(( but dvd, vcd and so on should work perfectly
31 * (if you have the bandwidth ;)
32 * A simple server is in TOOLS/netstream.
39 #include <sys/types.h>
50 #define closesocket close
51 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
65 #include "netstream.h"
68 static struct stream_priv_s
{
72 } stream_priv_dflts
= {
78 #define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f)
80 static m_option_t stream_opts_fields
[] = {
81 {"hostname", ST_OFF(host
), CONF_TYPE_STRING
, 0, 0 ,0, NULL
},
82 {"port", ST_OFF(port
), CONF_TYPE_INT
, M_OPT_MIN
, 1 ,0, NULL
},
83 {"filename", ST_OFF(url
), CONF_TYPE_STRING
, 0, 0 ,0, NULL
},
84 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
86 static struct m_struct_st stream_opts
= {
88 sizeof(struct stream_priv_s
),
93 //// When the cache is running we need a lock as
94 //// fill_buffer is called from another proccess
95 static int lock_fd(int fd
) {
99 memset(&lock
,0,sizeof(struct flock
));
100 lock
.l_type
= F_WRLCK
;
102 mp_msg(MSGT_STREAM
,MSGL_DBG2
, "Lock (%d)\n",getpid());
104 if(fcntl(fd
,F_SETLKW
,&lock
)) {
105 if(errno
== EAGAIN
) continue;
106 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Failed to get the lock: %s\n",
111 mp_msg(MSGT_STREAM
,MSGL_DBG2
, "Locked (%d)\n",getpid());
113 printf("FIXME? should lock here\n");
118 static int unlock_fd(int fd
) {
119 #ifndef HAVE_WINSOCK2
122 memset(&lock
,0,sizeof(struct flock
));
123 lock
.l_type
= F_UNLCK
;
125 mp_msg(MSGT_STREAM
,MSGL_DBG2
, "Unlock (%d)\n",getpid());
126 if(fcntl(fd
,F_SETLK
,&lock
)) {
127 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Failed to release the lock: %s\n",
132 printf("FIXME? should unlock here\n");
137 static mp_net_stream_packet_t
* send_net_stream_cmd(stream_t
*s
,uint16_t cmd
,char* data
,int len
) {
138 mp_net_stream_packet_t
* pack
;
140 // Cache is enabled : lock
141 if(s
->cache_data
&& !lock_fd(s
->fd
))
144 if(!write_packet(s
->fd
,cmd
,data
,len
)) {
145 if(s
->cache_data
) unlock_fd(s
->fd
);
149 pack
= read_packet(s
->fd
);
151 if(s
->cache_data
) unlock_fd(s
->fd
);
159 case NET_STREAM_ERROR
:
160 if(pack
->len
> sizeof(mp_net_stream_packet_t
))
161 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Fill buffer failed: %s\n",pack
->data
);
163 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Fill buffer failed\n");
168 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Unknown response to %d: %d\n",cmd
,pack
->cmd
);
173 static int fill_buffer(stream_t
*s
, char* buffer
, int max_len
){
174 uint16_t len
= le2me_16(max_len
);
175 mp_net_stream_packet_t
* pack
;
177 pack
= send_net_stream_cmd(s
,NET_STREAM_FILL_BUFFER
,(char*)&len
,2);
181 len
= pack
->len
- sizeof(mp_net_stream_packet_t
);
183 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Got a too big a packet %d / %d\n",len
,max_len
);
188 memcpy(buffer
,pack
->data
,len
);
194 static int seek(stream_t
*s
,off_t newpos
) {
195 uint64_t pos
= le2me_64((uint64_t)newpos
);
196 mp_net_stream_packet_t
* pack
;
198 pack
= send_net_stream_cmd(s
,NET_STREAM_SEEK
,(char*)&pos
,8);
207 static int net_stream_reset(struct stream_st
*s
) {
208 mp_net_stream_packet_t
* pack
;
210 pack
= send_net_stream_cmd(s
,NET_STREAM_RESET
,NULL
,0);
218 static int control(struct stream_st
*s
,int cmd
,void* arg
) {
220 case STREAM_CTRL_RESET
:
221 return net_stream_reset(s
);
223 return STREAM_UNSUPORTED
;
226 static void close_s(struct stream_st
*s
) {
227 mp_net_stream_packet_t
* pack
;
229 pack
= send_net_stream_cmd(s
,NET_STREAM_CLOSE
,NULL
,0);
234 static int open_s(stream_t
*stream
,int mode
, void* opts
, int* file_format
) {
236 struct stream_priv_s
* p
= (struct stream_priv_s
*)opts
;
237 mp_net_stream_packet_t
* pack
;
238 mp_net_stream_opened_t
* opened
;
240 if(mode
!= STREAM_READ
)
241 return STREAM_UNSUPORTED
;
244 mp_msg(MSGT_OPEN
,MSGL_ERR
, "We need an host name (ex: mpst://server.net/cdda://5)\n");
245 m_struct_free(&stream_opts
,opts
);
248 if(!p
->url
|| strlen(p
->url
) == 0) {
249 mp_msg(MSGT_OPEN
,MSGL_ERR
, "We need a remote url (ex: mpst://server.net/cdda://5)\n");
250 m_struct_free(&stream_opts
,opts
);
254 f
= connect2Server(p
->host
,p
->port
,1);
256 mp_msg(MSGT_OPEN
,MSGL_ERR
, "Connection to %s:%d failed\n",p
->host
,p
->port
);
257 m_struct_free(&stream_opts
,opts
);
261 /// Now send an open command
262 pack
= send_net_stream_cmd(stream
,NET_STREAM_OPEN
,p
->url
,strlen(p
->url
) + 1);
267 if(pack
->len
!= sizeof(mp_net_stream_packet_t
) +
268 sizeof(mp_net_stream_opened_t
)) {
269 mp_msg(MSGT_OPEN
,MSGL_ERR
, "Invalid open response packet len (%d bytes)\n",pack
->len
);
274 opened
= (mp_net_stream_opened_t
*)pack
->data
;
275 net_stream_opened_2_me(opened
);
277 *file_format
= opened
->file_format
;
278 stream
->flags
= opened
->flags
;
279 stream
->sector_size
= opened
->sector_size
;
280 stream
->start_pos
= opened
->start_pos
;
281 stream
->end_pos
= opened
->end_pos
;
283 stream
->fill_buffer
= fill_buffer
;
284 stream
->control
= control
;
285 if(stream
->flags
& STREAM_SEEK
)
287 stream
->close
= close_s
;
290 m_struct_free(&stream_opts
,opts
);
296 m_struct_free(&stream_opts
,opts
);
300 stream_info_t stream_info_netstream
= {
308 1 // Url is an option string