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