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
24 * Net stream allow you to access MPlayer stream accross a tcp
26 * Note that at least mf and tv use a dummy stream (they are
27 * implemented at the demuxer level) so you won't be able to
28 * access those :(( but dvd, vcd and so on should work perfectly
29 * (if you have the bandwidth ;)
30 * A simple server is in TOOLS/netstream.
37 #include <sys/types.h>
48 #define closesocket close
49 #include <sys/socket.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
61 #include "libavutil/common.h"
64 #include "netstream.h"
67 static struct stream_priv_s
{
71 } stream_priv_dflts
= {
77 #define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f)
79 static const m_option_t stream_opts_fields
[] = {
80 {"hostname", ST_OFF(host
), CONF_TYPE_STRING
, 0, 0 ,0, NULL
},
81 {"port", ST_OFF(port
), CONF_TYPE_INT
, M_OPT_MIN
, 1 ,0, NULL
},
82 {"filename", ST_OFF(url
), CONF_TYPE_STRING
, 0, 0 ,0, NULL
},
83 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
85 static struct m_struct_st stream_opts
= {
87 sizeof(struct stream_priv_s
),
92 //// When the cache is running we need a lock as
93 //// fill_buffer is called from another proccess
94 static int lock_fd(int fd
) {
98 memset(&lock
,0,sizeof(struct flock
));
99 lock
.l_type
= F_WRLCK
;
101 mp_msg(MSGT_STREAM
,MSGL_DBG2
, "Lock (%d)\n",getpid());
103 if(fcntl(fd
,F_SETLKW
,&lock
)) {
104 if(errno
== EAGAIN
) continue;
105 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Failed to get the lock: %s\n",
110 mp_msg(MSGT_STREAM
,MSGL_DBG2
, "Locked (%d)\n",getpid());
112 printf("FIXME? should lock here\n");
117 static int unlock_fd(int fd
) {
118 #ifndef HAVE_WINSOCK2
121 memset(&lock
,0,sizeof(struct flock
));
122 lock
.l_type
= F_UNLCK
;
124 mp_msg(MSGT_STREAM
,MSGL_DBG2
, "Unlock (%d)\n",getpid());
125 if(fcntl(fd
,F_SETLK
,&lock
)) {
126 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Failed to release the lock: %s\n",
131 printf("FIXME? should unlock here\n");
136 static mp_net_stream_packet_t
* send_net_stream_cmd(stream_t
*s
,uint16_t cmd
,char* data
,int len
) {
137 mp_net_stream_packet_t
* pack
;
139 // Cache is enabled : lock
140 if(s
->cache_data
&& !lock_fd(s
->fd
))
143 if(!write_packet(s
->fd
,cmd
,data
,len
)) {
144 if(s
->cache_data
) unlock_fd(s
->fd
);
148 pack
= read_packet(s
->fd
);
150 if(s
->cache_data
) unlock_fd(s
->fd
);
158 case NET_STREAM_ERROR
:
159 if(pack
->len
> sizeof(mp_net_stream_packet_t
))
160 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Fill buffer failed: %s\n",pack
->data
);
162 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Fill buffer failed\n");
167 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Unknown response to %d: %d\n",cmd
,pack
->cmd
);
172 static int fill_buffer(stream_t
*s
, char* buffer
, int max_len
){
173 uint16_t len
= le2me_16(max_len
);
174 mp_net_stream_packet_t
* pack
;
176 pack
= send_net_stream_cmd(s
,NET_STREAM_FILL_BUFFER
,(char*)&len
,2);
180 len
= pack
->len
- sizeof(mp_net_stream_packet_t
);
182 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Got a too big a packet %d / %d\n",len
,max_len
);
187 memcpy(buffer
,pack
->data
,len
);
193 static int seek(stream_t
*s
,off_t newpos
) {
194 uint64_t pos
= le2me_64((uint64_t)newpos
);
195 mp_net_stream_packet_t
* pack
;
197 pack
= send_net_stream_cmd(s
,NET_STREAM_SEEK
,(char*)&pos
,8);
206 static int net_stream_reset(struct stream_st
*s
) {
207 mp_net_stream_packet_t
* pack
;
209 pack
= send_net_stream_cmd(s
,NET_STREAM_RESET
,NULL
,0);
217 static int control(struct stream_st
*s
,int cmd
,void* arg
) {
219 case STREAM_CTRL_RESET
:
220 return net_stream_reset(s
);
222 return STREAM_UNSUPPORTED
;
225 static void close_s(struct stream_st
*s
) {
226 mp_net_stream_packet_t
* pack
;
228 pack
= send_net_stream_cmd(s
,NET_STREAM_CLOSE
,NULL
,0);
233 static int open_s(stream_t
*stream
,int mode
, void* opts
, int* file_format
) {
235 struct stream_priv_s
* p
= (struct stream_priv_s
*)opts
;
236 mp_net_stream_packet_t
* pack
;
237 mp_net_stream_opened_t
* opened
;
239 if(mode
!= STREAM_READ
)
240 return STREAM_UNSUPPORTED
;
243 mp_msg(MSGT_OPEN
,MSGL_ERR
, "We need an host name (ex: mpst://server.net/cdda://5)\n");
244 m_struct_free(&stream_opts
,opts
);
247 if(!p
->url
|| strlen(p
->url
) == 0) {
248 mp_msg(MSGT_OPEN
,MSGL_ERR
, "We need a remote url (ex: mpst://server.net/cdda://5)\n");
249 m_struct_free(&stream_opts
,opts
);
253 f
= connect2Server(p
->host
,p
->port
,1);
255 mp_msg(MSGT_OPEN
,MSGL_ERR
, "Connection to %s:%d failed\n",p
->host
,p
->port
);
256 m_struct_free(&stream_opts
,opts
);
260 /// Now send an open command
261 pack
= send_net_stream_cmd(stream
,NET_STREAM_OPEN
,p
->url
,strlen(p
->url
) + 1);
266 if(pack
->len
!= sizeof(mp_net_stream_packet_t
) +
267 sizeof(mp_net_stream_opened_t
)) {
268 mp_msg(MSGT_OPEN
,MSGL_ERR
, "Invalid open response packet len (%d bytes)\n",pack
->len
);
273 opened
= (mp_net_stream_opened_t
*)pack
->data
;
274 net_stream_opened_2_me(opened
);
276 *file_format
= opened
->file_format
;
277 stream
->flags
= opened
->flags
;
278 stream
->sector_size
= opened
->sector_size
;
279 stream
->start_pos
= opened
->start_pos
;
280 stream
->end_pos
= opened
->end_pos
;
282 stream
->fill_buffer
= fill_buffer
;
283 stream
->control
= control
;
284 if(stream
->flags
& STREAM_SEEK
)
286 stream
->close
= close_s
;
289 m_struct_free(&stream_opts
,opts
);
295 m_struct_free(&stream_opts
,opts
);
299 const stream_info_t stream_info_netstream
= {
307 1 // Url is an option string