1 /* Imported from the dvbstream-0.2 project
3 * Modified for use with MPlayer, for details see the CVS changelog at
4 * http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/
13 #include <sys/types.h>
17 #include <netinet/in.h>
18 #include <sys/socket.h>
19 #include <arpa/inet.h>
20 #define closesocket close
28 /* MPEG-2 TS RTP stack */
33 extern int network_bandwidth
;
35 int read_rtp_from_server(int fd
, char *buffer
, int length
) {
39 static int got_first
= 0;
40 static unsigned short sequence
;
42 if( buffer
==NULL
|| length
<0 ) return -1;
44 getrtp2(fd
, &rh
, &data
, &len
);
45 if( got_first
&& rh
.b
.sequence
!= (unsigned short)(sequence
+1) )
46 mp_msg(MSGT_NETWORK
,MSGL_ERR
,"RTP packet sequence error! Expected: %d, received: %d\n",
47 sequence
+1, rh
.b
.sequence
);
49 sequence
= rh
.b
.sequence
;
50 memcpy(buffer
, data
, len
);
55 // Start listening on a UDP port. If multicast, join the group.
56 static int rtp_open_socket( URL_t
*url
) {
57 int socket_server_fd
, rxsockbufsz
;
60 struct sockaddr_in server_address
;
65 mp_msg(MSGT_NETWORK
,MSGL_V
,"Listening for traffic on %s:%d ...\n", url
->hostname
, url
->port
);
67 socket_server_fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
68 // fcntl( socket_server_fd, F_SETFL, fcntl(socket_server_fd, F_GETFL) | O_NONBLOCK );
69 if( socket_server_fd
==-1 ) {
70 mp_msg(MSGT_NETWORK
,MSGL_ERR
,"Failed to create socket\n");
74 if( isalpha(url
->hostname
[0]) ) {
76 hp
=(struct hostent
*)gethostbyname( url
->hostname
);
78 mp_msg(MSGT_NETWORK
,MSGL_ERR
,"Counldn't resolve name: %s\n", url
->hostname
);
81 memcpy( (void*)&server_address
.sin_addr
.s_addr
, (void*)hp
->h_addr_list
[0], hp
->h_length
);
83 server_address
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
88 inet_aton(url
->hostname
, &server_address
.sin_addr
);
90 inet_pton(AF_INET
, url
->hostname
, &server_address
.sin_addr
);
93 server_address
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
96 server_address
.sin_family
=AF_INET
;
97 server_address
.sin_port
=htons(url
->port
);
99 if( bind( socket_server_fd
, (struct sockaddr
*)&server_address
, sizeof(server_address
) )==-1 ) {
100 #ifndef HAVE_WINSOCK2
101 if( errno
!=EINPROGRESS
) {
103 if( WSAGetLastError() != WSAEINPROGRESS
) {
105 mp_msg(MSGT_NETWORK
,MSGL_ERR
,"Failed to connect to server\n");
111 if (isalpha(url
->hostname
[0])) {
112 hp
=(struct hostent
*)gethostbyname( url
->hostname
);
114 mp_msg(MSGT_NETWORK
,MSGL_ERR
,"Counldn't resolve name: %s\n", url
->hostname
);
117 memcpy( (void*)&server_address
.sin_addr
.s_addr
, (void*)hp
->h_addr
, hp
->h_length
);
119 unsigned int addr
= inet_addr(url
->hostname
);
120 memcpy( (void*)&server_address
.sin_addr
, (void*)&addr
, sizeof(addr
) );
124 // Increase the socket rx buffer size to maximum -- this is UDP
125 rxsockbufsz
= 240 * 1024;
126 if( setsockopt( socket_server_fd
, SOL_SOCKET
, SO_RCVBUF
, &rxsockbufsz
, sizeof(rxsockbufsz
))) {
127 mp_msg(MSGT_NETWORK
,MSGL_ERR
,"Couldn't set receive socket buffer size\n");
130 if((ntohl(server_address
.sin_addr
.s_addr
) >> 28) == 0xe) {
131 mcast
.imr_multiaddr
.s_addr
= server_address
.sin_addr
.s_addr
;
132 //mcast.imr_interface.s_addr = inet_addr("10.1.1.2");
133 mcast
.imr_interface
.s_addr
= 0;
134 if( setsockopt( socket_server_fd
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &mcast
, sizeof(mcast
))) {
135 mp_msg(MSGT_NETWORK
,MSGL_ERR
,"IP_ADD_MEMBERSHIP failed (do you have multicasting enabled in your kernel?)\n");
141 tv
.tv_usec
= (1 * 1000000); // 1 second timeout
143 FD_SET( socket_server_fd
, &set
);
144 err
= select(socket_server_fd
+1, &set
, NULL
, NULL
, &tv
);
146 mp_msg(MSGT_NETWORK
, MSGL_FATAL
, "Select failed: %s\n", strerror(errno
));
150 mp_msg(MSGT_NETWORK
,MSGL_ERR
,"Timeout! No data from host %s\n", url
->hostname
);
153 err_len
= sizeof( err
);
154 getsockopt( socket_server_fd
, SOL_SOCKET
, SO_ERROR
, &err
, &err_len
);
156 mp_msg(MSGT_NETWORK
,MSGL_DBG2
,"Socket error: %d\n", err
);
159 return socket_server_fd
;
162 closesocket(socket_server_fd
);
166 static int rtp_streaming_read( int fd
, char *buffer
, int size
, streaming_ctrl_t
*streaming_ctrl
) {
167 return read_rtp_from_server( fd
, buffer
, size
);
170 static int rtp_streaming_start( stream_t
*stream
, int raw_udp
) {
171 streaming_ctrl_t
*streaming_ctrl
;
174 if( stream
==NULL
) return -1;
175 streaming_ctrl
= stream
->streaming_ctrl
;
179 fd
= rtp_open_socket( (streaming_ctrl
->url
) );
180 if( fd
<0 ) return -1;
185 streaming_ctrl
->streaming_read
= nop_streaming_read
;
187 streaming_ctrl
->streaming_read
= rtp_streaming_read
;
188 streaming_ctrl
->streaming_seek
= nop_streaming_seek
;
189 streaming_ctrl
->prebuffer_size
= 64*1024; // 64 KBytes
190 streaming_ctrl
->buffering
= 0;
191 streaming_ctrl
->status
= streaming_playing_e
;
196 int getrtp2(int fd
, struct rtpheader
*rh
, char** data
, int* lengthData
) {
197 static char buf
[1600];
199 char* charP
= (char*) &intP
;
202 lengthPacket
=recv(fd
,buf
,1590,0);
205 if (lengthPacket
<0) {
206 fprintf(stderr
,"socket read error\n");
209 if (lengthPacket
<12) {
210 fprintf(stderr
,"packet too small (%d) to be an rtp frame (>12bytes)\n", lengthPacket
);
213 rh
->b
.v
= (unsigned int) ((buf
[0]>>6)&0x03);
214 rh
->b
.p
= (unsigned int) ((buf
[0]>>5)&0x01);
215 rh
->b
.x
= (unsigned int) ((buf
[0]>>4)&0x01);
216 rh
->b
.cc
= (unsigned int) ((buf
[0]>>0)&0x0f);
217 rh
->b
.m
= (unsigned int) ((buf
[1]>>7)&0x01);
218 rh
->b
.pt
= (unsigned int) ((buf
[1]>>0)&0x7f);
220 memcpy(charP
+2,&buf
[2],2);
221 rh
->b
.sequence
= ntohl(intP
);
223 memcpy(charP
,&buf
[4],4);
224 rh
->timestamp
= ntohl(intP
);
226 headerSize
= 12 + 4*rh
->b
.cc
; /* in bytes */
228 *lengthData
= lengthPacket
- headerSize
;
229 *data
= (char*) buf
+ headerSize
;
231 // fprintf(stderr,"Reading rtp: v=%x p=%x x=%x cc=%x m=%x pt=%x seq=%x ts=%x lgth=%d\n",rh->b.v,rh->b.p,rh->b.x,rh->b.cc,rh->b.m,rh->b.pt,rh->b.sequence,rh->timestamp,lengthPacket);
237 static int open_s(stream_t
*stream
,int mode
, void* opts
, int* file_format
) {
241 mp_msg(MSGT_OPEN
, MSGL_INFO
, "STREAM_RTP, URL: %s\n", stream
->url
);
242 stream
->streaming_ctrl
= streaming_ctrl_new();
243 if( stream
->streaming_ctrl
==NULL
) {
246 stream
->streaming_ctrl
->bandwidth
= network_bandwidth
;
247 url
= url_new(stream
->url
);
248 stream
->streaming_ctrl
->url
= check4proxies(url
);
251 mp_msg(MSGT_NETWORK
,MSGL_ERR
,"You must enter a port number for RTP and UDP streams!\n");
254 if(!strncmp(stream
->url
, "udp", 3))
257 if(rtp_streaming_start(stream
, udp
) < 0) {
258 mp_msg(MSGT_NETWORK
,MSGL_ERR
,"rtp_streaming_start(rtp) failed\n");
262 stream
->type
= STREAMTYPE_STREAM
;
263 fixup_network_stream_cache(stream
);
267 streaming_ctrl_free( stream
->streaming_ctrl
);
268 stream
->streaming_ctrl
= NULL
;
269 return STREAM_UNSUPORTED
;
273 stream_info_t stream_info_rtp_udp
= {
274 "mpeg rtp and upd streaming",
277 "native rtp support",
279 {"rtp", "udp", NULL
},
281 0 // Urls are an option string