Mercurial > mplayer.hg
comparison stream/stream_netstream.c @ 19271:64d82a45a05d
introduce new 'stream' directory for all stream layer related components and split them from libmpdemux
author | ben |
---|---|
date | Mon, 31 Jul 2006 17:39:17 +0000 |
parents | libmpdemux/stream_netstream.c@d2d9d011203f |
children | 2a9d669e5ff6 |
comparison
equal
deleted
inserted
replaced
19270:7d39b911f0bd | 19271:64d82a45a05d |
---|---|
1 /* | |
2 * stream_netstream.c | |
3 * | |
4 * Copyright (C) Alban Bedel - 04/2003 | |
5 * | |
6 * This file is part of MPlayer, a free movie player. | |
7 * | |
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) | |
11 * any later version. | |
12 * | |
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. | |
17 * | |
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. | |
21 * | |
22 * | |
23 */ | |
24 | |
25 /* | |
26 * Net stream allow you to access MPlayer stream accross a tcp | |
27 * connection. | |
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. | |
33 * | |
34 */ | |
35 | |
36 | |
37 #include "config.h" | |
38 | |
39 #include <sys/types.h> | |
40 #include <sys/stat.h> | |
41 #include <fcntl.h> | |
42 #include <unistd.h> | |
43 | |
44 #include <stdlib.h> | |
45 #include <stdio.h> | |
46 #include <inttypes.h> | |
47 #include <errno.h> | |
48 | |
49 #ifndef HAVE_WINSOCK2 | |
50 #define closesocket close | |
51 #include <sys/socket.h> | |
52 #include <netinet/in.h> | |
53 #include <arpa/inet.h> | |
54 #else | |
55 #include <winsock2.h> | |
56 #endif | |
57 | |
58 #include "mp_msg.h" | |
59 #include "stream.h" | |
60 #include "help_mp.h" | |
61 #include "m_option.h" | |
62 #include "m_struct.h" | |
63 #include "bswap.h" | |
64 | |
65 #include "netstream.h" | |
66 | |
67 static struct stream_priv_s { | |
68 char* host; | |
69 int port; | |
70 char* url; | |
71 } stream_priv_dflts = { | |
72 NULL, | |
73 10000, | |
74 NULL | |
75 }; | |
76 | |
77 #define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) | |
78 /// URL definition | |
79 static 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 } | |
84 }; | |
85 static struct m_struct_st stream_opts = { | |
86 "netstream", | |
87 sizeof(struct stream_priv_s), | |
88 &stream_priv_dflts, | |
89 stream_opts_fields | |
90 }; | |
91 | |
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) { | |
95 #ifndef HAVE_WINSOCK2 | |
96 struct flock lock; | |
97 | |
98 memset(&lock,0,sizeof(struct flock)); | |
99 lock.l_type = F_WRLCK; | |
100 | |
101 mp_msg(MSGT_STREAM,MSGL_DBG2, "Lock (%d)\n",getpid()); | |
102 do { | |
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", | |
106 strerror(errno)); | |
107 return 0; | |
108 } | |
109 } while(0); | |
110 mp_msg(MSGT_STREAM,MSGL_DBG2, "Locked (%d)\n",getpid()); | |
111 #else | |
112 printf("FIXME? should lock here\n"); | |
113 #endif | |
114 return 1; | |
115 } | |
116 | |
117 static int unlock_fd(int fd) { | |
118 #ifndef HAVE_WINSOCK2 | |
119 struct flock lock; | |
120 | |
121 memset(&lock,0,sizeof(struct flock)); | |
122 lock.l_type = F_UNLCK; | |
123 | |
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", | |
127 strerror(errno)); | |
128 return 0; | |
129 } | |
130 #else | |
131 printf("FIXME? should unlock here\n"); | |
132 #endif | |
133 return 1; | |
134 } | |
135 | |
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; | |
138 | |
139 // Cache is enabled : lock | |
140 if(s->cache_data && !lock_fd(s->fd)) | |
141 return NULL; | |
142 // Send a command | |
143 if(!write_packet(s->fd,cmd,data,len)) { | |
144 if(s->cache_data) unlock_fd(s->fd); | |
145 return 0; | |
146 } | |
147 // Read the response | |
148 pack = read_packet(s->fd); | |
149 // Now we can unlock | |
150 if(s->cache_data) unlock_fd(s->fd); | |
151 | |
152 if(!pack) | |
153 return NULL; | |
154 | |
155 switch(pack->cmd) { | |
156 case NET_STREAM_OK: | |
157 return pack; | |
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); | |
161 else | |
162 mp_msg(MSGT_STREAM,MSGL_ERR, "Fill buffer failed\n"); | |
163 free(pack); | |
164 return NULL; | |
165 } | |
166 | |
167 mp_msg(MSGT_STREAM,MSGL_ERR, "Unknown response to %d: %d\n",cmd,pack->cmd); | |
168 free(pack); | |
169 return NULL; | |
170 } | |
171 | |
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; | |
175 | |
176 pack = send_net_stream_cmd(s,NET_STREAM_FILL_BUFFER,(char*)&len,2); | |
177 if(!pack) { | |
178 return -1; | |
179 } | |
180 len = pack->len - sizeof(mp_net_stream_packet_t); | |
181 if(len > max_len) { | |
182 mp_msg(MSGT_STREAM,MSGL_ERR, "Got a too big a packet %d / %d\n",len,max_len); | |
183 free(pack); | |
184 return 0; | |
185 } | |
186 if(len > 0) | |
187 memcpy(buffer,pack->data,len); | |
188 free(pack); | |
189 return len; | |
190 } | |
191 | |
192 | |
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; | |
196 | |
197 pack = send_net_stream_cmd(s,NET_STREAM_SEEK,(char*)&pos,8); | |
198 if(!pack) { | |
199 return 0; | |
200 } | |
201 s->pos = newpos; | |
202 free(pack); | |
203 return 1; | |
204 } | |
205 | |
206 static int net_stream_reset(struct stream_st *s) { | |
207 mp_net_stream_packet_t* pack; | |
208 | |
209 pack = send_net_stream_cmd(s,NET_STREAM_RESET,NULL,0); | |
210 if(!pack) { | |
211 return 0; | |
212 } | |
213 free(pack); | |
214 return 1; | |
215 } | |
216 | |
217 static int control(struct stream_st *s,int cmd,void* arg) { | |
218 switch(cmd) { | |
219 case STREAM_CTRL_RESET: | |
220 return net_stream_reset(s); | |
221 } | |
222 return STREAM_UNSUPORTED; | |
223 } | |
224 | |
225 static void close_s(struct stream_st *s) { | |
226 mp_net_stream_packet_t* pack; | |
227 | |
228 pack = send_net_stream_cmd(s,NET_STREAM_CLOSE,NULL,0); | |
229 if(pack) | |
230 free(pack); | |
231 } | |
232 | |
233 static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { | |
234 int f; | |
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; | |
238 | |
239 if(mode != STREAM_READ) | |
240 return STREAM_UNSUPORTED; | |
241 | |
242 if(!p->host) { | |
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); | |
245 return STREAM_ERROR; | |
246 } | |
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); | |
250 return STREAM_ERROR; | |
251 } | |
252 | |
253 f = connect2Server(p->host,p->port,1); | |
254 if(f < 0) { | |
255 mp_msg(MSGT_OPEN,MSGL_ERR, "Connection to %s:%d failed\n",p->host,p->port); | |
256 m_struct_free(&stream_opts,opts); | |
257 return STREAM_ERROR; | |
258 } | |
259 stream->fd = f; | |
260 /// Now send an open command | |
261 pack = send_net_stream_cmd(stream,NET_STREAM_OPEN,p->url,strlen(p->url) + 1); | |
262 if(!pack) { | |
263 goto error; | |
264 } | |
265 | |
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); | |
269 free(pack); | |
270 goto error; | |
271 } | |
272 | |
273 opened = (mp_net_stream_opened_t*)pack->data; | |
274 net_stream_opened_2_me(opened); | |
275 | |
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; | |
281 | |
282 stream->fill_buffer = fill_buffer; | |
283 stream->control = control; | |
284 if(stream->flags & STREAM_SEEK) | |
285 stream->seek = seek; | |
286 stream->close = close_s; | |
287 | |
288 free(pack); | |
289 m_struct_free(&stream_opts,opts); | |
290 | |
291 return STREAM_OK; | |
292 | |
293 error: | |
294 closesocket(f); | |
295 m_struct_free(&stream_opts,opts); | |
296 return STREAM_ERROR; | |
297 } | |
298 | |
299 stream_info_t stream_info_netstream = { | |
300 "Net stream", | |
301 "netstream", | |
302 "Albeu", | |
303 "", | |
304 open_s, | |
305 { "mpst",NULL }, | |
306 &stream_opts, | |
307 1 // Url is an option string | |
308 }; |