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>
58 #include "libavutil/common.h"
62 #include "stream_netstream.h"
65 static struct stream_priv_s
{
69 } stream_priv_dflts
= {
75 #define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f)
77 static const m_option_t stream_opts_fields
[] = {
78 {"hostname", ST_OFF(host
), CONF_TYPE_STRING
, 0, 0 ,0, NULL
},
79 {"port", ST_OFF(port
), CONF_TYPE_INT
, M_OPT_MIN
, 1 ,0, NULL
},
80 {"filename", ST_OFF(url
), CONF_TYPE_STRING
, 0, 0 ,0, NULL
},
81 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
83 static const struct m_struct_st stream_opts
= {
85 sizeof(struct stream_priv_s
),
90 //// When the cache is running we need a lock as
91 //// fill_buffer is called from another proccess
92 static int lock_fd(int fd
) {
96 memset(&lock
,0,sizeof(struct flock
));
97 lock
.l_type
= F_WRLCK
;
99 mp_msg(MSGT_STREAM
,MSGL_DBG2
, "Lock (%d)\n",getpid());
101 if(fcntl(fd
,F_SETLKW
,&lock
)) {
102 if(errno
== EAGAIN
) continue;
103 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Failed to get the lock: %s\n",
108 mp_msg(MSGT_STREAM
,MSGL_DBG2
, "Locked (%d)\n",getpid());
110 printf("FIXME? should lock here\n");
115 static int unlock_fd(int fd
) {
119 memset(&lock
,0,sizeof(struct flock
));
120 lock
.l_type
= F_UNLCK
;
122 mp_msg(MSGT_STREAM
,MSGL_DBG2
, "Unlock (%d)\n",getpid());
123 if(fcntl(fd
,F_SETLK
,&lock
)) {
124 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Failed to release the lock: %s\n",
129 printf("FIXME? should unlock here\n");
134 static mp_net_stream_packet_t
* send_net_stream_cmd(stream_t
*s
,uint16_t cmd
,char* data
,int len
) {
135 mp_net_stream_packet_t
* pack
;
137 // Cache is enabled : lock
138 if(s
->cache_data
&& !lock_fd(s
->fd
))
141 if(!write_packet(s
->fd
,cmd
,data
,len
)) {
142 if(s
->cache_data
) unlock_fd(s
->fd
);
146 pack
= read_packet(s
->fd
);
148 if(s
->cache_data
) unlock_fd(s
->fd
);
156 case NET_STREAM_ERROR
:
157 if(pack
->len
> sizeof(mp_net_stream_packet_t
))
158 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Fill buffer failed: %s\n",pack
->data
);
160 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Fill buffer failed\n");
165 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Unknown response to %d: %d\n",cmd
,pack
->cmd
);
170 static int fill_buffer(stream_t
*s
, char* buffer
, int max_len
){
171 uint16_t len
= le2me_16(max_len
);
172 mp_net_stream_packet_t
* pack
;
174 pack
= send_net_stream_cmd(s
,NET_STREAM_FILL_BUFFER
,(char*)&len
,2);
178 len
= pack
->len
- sizeof(mp_net_stream_packet_t
);
180 mp_msg(MSGT_STREAM
,MSGL_ERR
, "Got a too big a packet %d / %d\n",len
,max_len
);
185 memcpy(buffer
,pack
->data
,len
);
191 static int seek(stream_t
*s
,off_t newpos
) {
192 uint64_t pos
= le2me_64((uint64_t)newpos
);
193 mp_net_stream_packet_t
* pack
;
195 pack
= send_net_stream_cmd(s
,NET_STREAM_SEEK
,(char*)&pos
,8);
204 static int net_stream_reset(struct stream_st
*s
) {
205 mp_net_stream_packet_t
* pack
;
207 pack
= send_net_stream_cmd(s
,NET_STREAM_RESET
,NULL
,0);
215 static int control(struct stream_st
*s
,int cmd
,void* arg
) {
217 case STREAM_CTRL_RESET
:
218 return net_stream_reset(s
);
220 return STREAM_UNSUPPORTED
;
223 static void close_s(struct stream_st
*s
) {
224 mp_net_stream_packet_t
* pack
;
226 pack
= send_net_stream_cmd(s
,NET_STREAM_CLOSE
,NULL
,0);
231 static int open_s(stream_t
*stream
,int mode
, void* opts
, int* file_format
) {
233 struct stream_priv_s
* p
= (struct stream_priv_s
*)opts
;
234 mp_net_stream_packet_t
* pack
;
235 mp_net_stream_opened_t
* opened
;
237 if(mode
!= STREAM_READ
)
238 return STREAM_UNSUPPORTED
;
241 mp_msg(MSGT_OPEN
,MSGL_ERR
, "We need an host name (ex: mpst://server.net/cdda://5)\n");
242 m_struct_free(&stream_opts
,opts
);
245 if(!p
->url
|| strlen(p
->url
) == 0) {
246 mp_msg(MSGT_OPEN
,MSGL_ERR
, "We need a remote url (ex: mpst://server.net/cdda://5)\n");
247 m_struct_free(&stream_opts
,opts
);
251 f
= connect2Server(p
->host
,p
->port
,1);
253 mp_msg(MSGT_OPEN
,MSGL_ERR
, "Connection to %s:%d failed\n",p
->host
,p
->port
);
254 m_struct_free(&stream_opts
,opts
);
258 /// Now send an open command
259 pack
= send_net_stream_cmd(stream
,NET_STREAM_OPEN
,p
->url
,strlen(p
->url
) + 1);
264 if(pack
->len
!= sizeof(mp_net_stream_packet_t
) +
265 sizeof(mp_net_stream_opened_t
)) {
266 mp_msg(MSGT_OPEN
,MSGL_ERR
, "Invalid open response packet len (%d bytes)\n",pack
->len
);
271 opened
= (mp_net_stream_opened_t
*)pack
->data
;
272 net_stream_opened_2_me(opened
);
274 *file_format
= opened
->file_format
;
275 stream
->flags
= opened
->flags
;
276 stream
->sector_size
= opened
->sector_size
;
277 stream
->start_pos
= opened
->start_pos
;
278 stream
->end_pos
= opened
->end_pos
;
280 stream
->fill_buffer
= fill_buffer
;
281 stream
->control
= control
;
282 if(stream
->flags
& STREAM_SEEK
)
284 stream
->close
= close_s
;
287 m_struct_free(&stream_opts
,opts
);
293 m_struct_free(&stream_opts
,opts
);
297 const stream_info_t stream_info_netstream
= {
305 1 // Url is an option string