2 * Copyright (C) Alban Bedel - 04/2003
4 * This file is part of MPlayer.
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * Net stream allow you to access MPlayer stream accross a tcp
24 * Note that at least mf and tv use a dummy stream (they are
25 * implemented at the demuxer level) so you won't be able to
26 * access those :(( but dvd, vcd and so on should work perfectly
27 * (if you have the bandwidth ;)
28 * A simple server is in TOOLS/netstream.
35 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
57 #include "libavutil/common.h"
61 #include "stream_netstream.h"
64 static struct stream_priv_s
{
68 } stream_priv_dflts
= {
74 #define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f)
76 static const m_option_t stream_opts_fields
[] = {
77 {"hostname", ST_OFF(host
), CONF_TYPE_STRING
, 0, 0 ,0, NULL
},
78 {"port", ST_OFF(port
), CONF_TYPE_INT
, M_OPT_MIN
, 1 ,0, NULL
},
79 {"filename", ST_OFF(url
), CONF_TYPE_STRING
, 0, 0 ,0, NULL
},
80 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
82 static const struct m_struct_st stream_opts
= {
84 sizeof(struct stream_priv_s
),
89 //// When the cache is running we need a lock as
90 //// fill_buffer is called from another proccess
91 static int lock_fd(int fd
) {
95 memset(&lock
,0,sizeof(struct flock
));
96 lock
.l_type
= F_WRLCK
;
98 mp_msg(MSGT_STREAM
,MSGL_DBG2
, "Lock (%d)\n",getpid());
100 if(fcntl(fd
,F_SETLKW
,&lock
)) {
101 if(errno
== EAGAIN
) continue;
102 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Failed to get the lock: %s\n",
107 mp_msg(MSGT_STREAM
,MSGL_DBG2
, "Locked (%d)\n",getpid());
109 printf("FIXME? should lock here\n");
114 static int unlock_fd(int fd
) {
118 memset(&lock
,0,sizeof(struct flock
));
119 lock
.l_type
= F_UNLCK
;
121 mp_msg(MSGT_STREAM
,MSGL_DBG2
, "Unlock (%d)\n",getpid());
122 if(fcntl(fd
,F_SETLK
,&lock
)) {
123 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Failed to release the lock: %s\n",
128 printf("FIXME? should unlock here\n");
133 static mp_net_stream_packet_t
* send_net_stream_cmd(stream_t
*s
,uint16_t cmd
,char* data
,int len
) {
134 mp_net_stream_packet_t
* pack
;
136 // Cache is enabled : lock
137 if(s
->cache_data
&& !lock_fd(s
->fd
))
140 if(!write_packet(s
->fd
,cmd
,data
,len
)) {
141 if(s
->cache_data
) unlock_fd(s
->fd
);
145 pack
= read_packet(s
->fd
);
147 if(s
->cache_data
) unlock_fd(s
->fd
);
155 case NET_STREAM_ERROR
:
156 if(pack
->len
> sizeof(mp_net_stream_packet_t
))
157 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Fill buffer failed: %s\n",pack
->data
);
159 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Fill buffer failed\n");
164 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Unknown response to %d: %d\n",cmd
,pack
->cmd
);
169 static int fill_buffer(stream_t
*s
, char* buffer
, int max_len
){
170 uint16_t len
= le2me_16(max_len
);
171 mp_net_stream_packet_t
* pack
;
173 pack
= send_net_stream_cmd(s
,NET_STREAM_FILL_BUFFER
,(char*)&len
,2);
177 len
= pack
->len
- sizeof(mp_net_stream_packet_t
);
179 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Got a too big a packet %d / %d\n",len
,max_len
);
184 memcpy(buffer
,pack
->data
,len
);
190 static int seek(stream_t
*s
,off_t newpos
) {
191 uint64_t pos
= le2me_64((uint64_t)newpos
);
192 mp_net_stream_packet_t
* pack
;
194 pack
= send_net_stream_cmd(s
,NET_STREAM_SEEK
,(char*)&pos
,8);
203 static int net_stream_reset(struct stream
*s
) {
204 mp_net_stream_packet_t
* pack
;
206 pack
= send_net_stream_cmd(s
,NET_STREAM_RESET
,NULL
,0);
214 static int control(struct stream
*s
,int cmd
,void* arg
) {
216 case STREAM_CTRL_RESET
:
217 return net_stream_reset(s
);
219 return STREAM_UNSUPPORTED
;
222 static void close_s(struct stream
*s
) {
223 mp_net_stream_packet_t
* pack
;
225 pack
= send_net_stream_cmd(s
,NET_STREAM_CLOSE
,NULL
,0);
230 static int open_s(stream_t
*stream
,int mode
, void* opts
, int* file_format
) {
232 struct stream_priv_s
* p
= (struct stream_priv_s
*)opts
;
233 mp_net_stream_packet_t
* pack
;
234 mp_net_stream_opened_t
* opened
;
236 if(mode
!= STREAM_READ
)
237 return STREAM_UNSUPPORTED
;
240 mp_msg(MSGT_OPEN
,MSGL_ERR
, "We need an host name (ex: mpst://server.net/cdda://5)\n");
241 m_struct_free(&stream_opts
,opts
);
244 if(!p
->url
|| strlen(p
->url
) == 0) {
245 mp_msg(MSGT_OPEN
,MSGL_ERR
, "We need a remote url (ex: mpst://server.net/cdda://5)\n");
246 m_struct_free(&stream_opts
,opts
);
250 f
= connect2Server(p
->host
,p
->port
,1);
252 mp_msg(MSGT_OPEN
,MSGL_ERR
, "Connection to %s:%d failed\n",p
->host
,p
->port
);
253 m_struct_free(&stream_opts
,opts
);
257 /// Now send an open command
258 pack
= send_net_stream_cmd(stream
,NET_STREAM_OPEN
,p
->url
,strlen(p
->url
) + 1);
263 if(pack
->len
!= sizeof(mp_net_stream_packet_t
) +
264 sizeof(mp_net_stream_opened_t
)) {
265 mp_msg(MSGT_OPEN
,MSGL_ERR
, "Invalid open response packet len (%d bytes)\n",pack
->len
);
270 opened
= (mp_net_stream_opened_t
*)pack
->data
;
271 net_stream_opened_2_me(opened
);
273 *file_format
= opened
->file_format
;
274 stream
->flags
= opened
->flags
;
275 stream
->sector_size
= opened
->sector_size
;
276 stream
->start_pos
= opened
->start_pos
;
277 stream
->end_pos
= opened
->end_pos
;
279 stream
->fill_buffer
= fill_buffer
;
280 stream
->control
= control
;
281 if(stream
->flags
& MP_STREAM_SEEK
)
283 stream
->close
= close_s
;
286 m_struct_free(&stream_opts
,opts
);
292 m_struct_free(&stream_opts
,opts
);
296 const stream_info_t stream_info_netstream
= {
304 1 // Url is an option string