Mercurial > mplayer.hg
comparison libmpdemux/stream_netstream.c @ 9850:564678d0bc15
A new stream wich allow access to MPlayer stream accross the network.
URL is mpst://host[:port]/remote_url where remote_url is any valid
MPlayer url.
author | albeu |
---|---|
date | Sun, 06 Apr 2003 16:33:13 +0000 |
parents | |
children | 4c6c6c361f24 |
comparison
equal
deleted
inserted
replaced
9849:5b649442fe72 | 9850:564678d0bc15 |
---|---|
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 #ifdef STREAMING | |
40 | |
41 #include <sys/types.h> | |
42 #include <sys/stat.h> | |
43 #include <fcntl.h> | |
44 #include <unistd.h> | |
45 | |
46 #include <stdlib.h> | |
47 #include <stdio.h> | |
48 #include <inttypes.h> | |
49 #include <errno.h> | |
50 | |
51 #include <sys/socket.h> | |
52 #include <netinet/in.h> | |
53 #include <arpa/inet.h> | |
54 | |
55 #include "mp_msg.h" | |
56 #include "stream.h" | |
57 #include "help_mp.h" | |
58 #include "../m_option.h" | |
59 #include "../m_struct.h" | |
60 | |
61 #include "netstream.h" | |
62 | |
63 static struct stream_priv_s { | |
64 char* host; | |
65 int port; | |
66 char* url; | |
67 } stream_priv_dflts = { | |
68 NULL, | |
69 10000, | |
70 NULL | |
71 }; | |
72 | |
73 #define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) | |
74 /// URL definition | |
75 static m_option_t stream_opts_fields[] = { | |
76 {"hostname", ST_OFF(host), CONF_TYPE_STRING, 0, 0 ,0, NULL}, | |
77 {"port", ST_OFF(port), CONF_TYPE_INT, M_OPT_MIN, 1 ,0, NULL}, | |
78 {"filename", ST_OFF(url), CONF_TYPE_STRING, 0, 0 ,0, NULL}, | |
79 { NULL, NULL, 0, 0, 0, 0, NULL } | |
80 }; | |
81 static struct m_struct_st stream_opts = { | |
82 "netstream", | |
83 sizeof(struct stream_priv_s), | |
84 &stream_priv_dflts, | |
85 stream_opts_fields | |
86 }; | |
87 | |
88 //// When the cache is running we need a lock as | |
89 //// fill_buffer is called from another proccess | |
90 static int lock_fd(int fd) { | |
91 struct flock lock; | |
92 | |
93 memset(&lock,0,sizeof(struct flock)); | |
94 lock.l_type = F_WRLCK; | |
95 | |
96 mp_msg(MSGT_STREAM,MSGL_DBG2, "Lock (%d)\n",getpid()); | |
97 do { | |
98 if(fcntl(fd,F_SETLKW,&lock)) { | |
99 if(errno == EAGAIN) continue; | |
100 mp_msg(MSGT_STREAM,MSGL_ERR, "Failed to get the lock: %s\n", | |
101 strerror(errno)); | |
102 return 0; | |
103 } | |
104 } while(0); | |
105 mp_msg(MSGT_STREAM,MSGL_DBG2, "Locked (%d)\n",getpid()); | |
106 return 1; | |
107 } | |
108 | |
109 static int unlock_fd(int fd) { | |
110 struct flock lock; | |
111 | |
112 memset(&lock,0,sizeof(struct flock)); | |
113 lock.l_type = F_UNLCK; | |
114 | |
115 mp_msg(MSGT_STREAM,MSGL_DBG2, "Unlock (%d)\n",getpid()); | |
116 if(fcntl(fd,F_SETLK,&lock)) { | |
117 mp_msg(MSGT_STREAM,MSGL_ERR, "Failed to release the lock: %s\n", | |
118 strerror(errno)); | |
119 return 0; | |
120 } | |
121 return 1; | |
122 } | |
123 | |
124 static mp_net_stream_packet_t* send_net_stream_cmd(stream_t *s,uint16_t cmd,char* data,int len) { | |
125 mp_net_stream_packet_t* pack; | |
126 | |
127 // Cache is enabled : lock | |
128 if(s->cache_data && !lock_fd(s->fd)) | |
129 return NULL; | |
130 // Send a command | |
131 if(!write_packet(s->fd,cmd,data,len)) { | |
132 if(s->cache_data) unlock_fd(s->fd); | |
133 return 0; | |
134 } | |
135 // Read the response | |
136 pack = read_packet(s->fd); | |
137 // Now we can unlock | |
138 if(s->cache_data) unlock_fd(s->fd); | |
139 | |
140 if(!pack) | |
141 return NULL; | |
142 | |
143 switch(pack->cmd) { | |
144 case NET_STREAM_OK: | |
145 return pack; | |
146 case NET_STREAM_ERROR: | |
147 if(pack->len > sizeof(mp_net_stream_packet_t)) | |
148 mp_msg(MSGT_STREAM,MSGL_ERR, "Fill buffer failed: %s\n",pack->data); | |
149 else | |
150 mp_msg(MSGT_STREAM,MSGL_ERR, "Fill buffer failed\n"); | |
151 free(pack); | |
152 return NULL; | |
153 } | |
154 | |
155 mp_msg(MSGT_STREAM,MSGL_ERR, "Unknow response to %d: %d\n",pack->cmd); | |
156 free(pack); | |
157 return NULL; | |
158 } | |
159 | |
160 static int fill_buffer(stream_t *s, char* buffer, int max_len){ | |
161 uint16_t len = max_len; | |
162 mp_net_stream_packet_t* pack; | |
163 | |
164 pack = send_net_stream_cmd(s,NET_STREAM_FILL_BUFFER,(char*)&len,2); | |
165 if(!pack) { | |
166 return -1; | |
167 } | |
168 len = pack->len - sizeof(mp_net_stream_packet_t); | |
169 if(len > max_len) { | |
170 mp_msg(MSGT_STREAM,MSGL_ERR, "Got a too big a packet %d / %d\n",len,max_len); | |
171 free(pack); | |
172 return 0; | |
173 } | |
174 if(len > 0) | |
175 memcpy(buffer,pack->data,len); | |
176 free(pack); | |
177 return len; | |
178 } | |
179 | |
180 | |
181 static int seek(stream_t *s,off_t newpos) { | |
182 uint64_t pos = (uint64_t)newpos; | |
183 mp_net_stream_packet_t* pack; | |
184 | |
185 pack = send_net_stream_cmd(s,NET_STREAM_SEEK,(char*)&pos,8); | |
186 if(!pack) { | |
187 return 0; | |
188 } | |
189 s->pos = newpos; | |
190 free(pack); | |
191 return 1; | |
192 } | |
193 | |
194 static int net_stream_reset(struct stream_st *s) { | |
195 mp_net_stream_packet_t* pack; | |
196 | |
197 pack = send_net_stream_cmd(s,NET_STREAM_RESET,NULL,0); | |
198 if(!pack) { | |
199 return 0; | |
200 } | |
201 free(pack); | |
202 return 1; | |
203 } | |
204 | |
205 static int control(struct stream_st *s,int cmd,void* arg) { | |
206 switch(cmd) { | |
207 case STREAM_CTRL_RESET: | |
208 return net_stream_reset(s); | |
209 } | |
210 return STREAM_UNSUPORTED; | |
211 } | |
212 | |
213 static void close_s(struct stream_st *s) { | |
214 mp_net_stream_packet_t* pack; | |
215 | |
216 pack = send_net_stream_cmd(s,NET_STREAM_CLOSE,NULL,0); | |
217 if(pack) | |
218 free(pack); | |
219 } | |
220 | |
221 static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { | |
222 int f; | |
223 struct stream_priv_s* p = (struct stream_priv_s*)opts; | |
224 mp_net_stream_packet_t* pack; | |
225 mp_net_stream_opened_t* opened; | |
226 | |
227 if(mode != STREAM_READ) | |
228 return STREAM_UNSUPORTED; | |
229 | |
230 if(!p->host) { | |
231 mp_msg(MSGT_OPEN,MSGL_ERR, "We need an host name (ex: mpst://server.net/cdda://5)\n"); | |
232 m_struct_free(&stream_opts,opts); | |
233 return STREAM_ERROR; | |
234 } | |
235 if(!p->url || strlen(p->url) == 0) { | |
236 mp_msg(MSGT_OPEN,MSGL_ERR, "We need a remote url (ex: mpst://server.net/cdda://5)\n"); | |
237 m_struct_free(&stream_opts,opts); | |
238 return STREAM_ERROR; | |
239 } | |
240 | |
241 f = connect2Server(p->host,p->port); | |
242 if(f < 0) { | |
243 mp_msg(MSGT_OPEN,MSGL_ERR, "Connection to %s:%d failed\n",p->host,p->port); | |
244 m_struct_free(&stream_opts,opts); | |
245 return STREAM_ERROR; | |
246 } | |
247 stream->fd = f; | |
248 /// Now send an open command | |
249 pack = send_net_stream_cmd(stream,NET_STREAM_OPEN,p->url,strlen(p->url) + 1); | |
250 if(!pack) { | |
251 goto error; | |
252 } | |
253 | |
254 if(pack->len != sizeof(mp_net_stream_packet_t) + | |
255 sizeof(mp_net_stream_opened_t)) { | |
256 mp_msg(MSGT_OPEN,MSGL_ERR, "Invalid open response packet len (%d bytes)\n",pack->len); | |
257 free(pack); | |
258 goto error; | |
259 } | |
260 | |
261 opened = (mp_net_stream_opened_t*)pack->data; | |
262 *file_format = opened->file_format; | |
263 stream->flags = opened->flags; | |
264 stream->sector_size = opened->sector_size; | |
265 stream->start_pos = opened->start_pos; | |
266 stream->end_pos = opened->end_pos; | |
267 | |
268 stream->fill_buffer = fill_buffer; | |
269 stream->control = control; | |
270 if(stream->flags & STREAM_SEEK) | |
271 stream->seek = seek; | |
272 stream->close = close_s; | |
273 | |
274 free(pack); | |
275 m_struct_free(&stream_opts,opts); | |
276 | |
277 return STREAM_OK; | |
278 | |
279 error: | |
280 close(f); | |
281 m_struct_free(&stream_opts,opts); | |
282 return STREAM_ERROR; | |
283 } | |
284 | |
285 stream_info_t stream_info_netstream = { | |
286 "Net stream", | |
287 "netstream", | |
288 "Albeu", | |
289 "", | |
290 open_s, | |
291 { "mpst",NULL }, | |
292 &stream_opts, | |
293 1 // Url is an option string | |
294 }; | |
295 | |
296 #endif |