1 /* Imported from the dvbstream-0.2 project
2  *
3  * Modified for use with MPlayer, for details see the changelog at
4  * http://svn.mplayerhq.hu/mplayer/trunk/
5  * $Id: rtp.c 29305 2009-05-13 02:58:57Z diego $
6  */
7 
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <sys/types.h>
14 #include <ctype.h>
15 #include "config.h"
16 #if !HAVE_WINSOCK2_H
17 #include <netinet/in.h>
18 #include <sys/socket.h>
19 #include <arpa/inet.h>
20 #else
21 #include <winsock2.h>
22 #include <ws2tcpip.h>
23 #endif
24 #include <errno.h>
25 #include "network.h"
26 #include "stream.h"
27 
28 /* MPEG-2 TS RTP stack */
29 
30 #define DEBUG        1
31 #include "mp_msg.h"
32 #include "rtp.h"
33 
34 // RTP reorder routines
35 // Also handling of repeated UDP packets (a bug of ExtremeNetworks switches firmware)
36 // rtpreord procedures
37 // write rtp packets in cache
38 // get rtp packets reordered
39 
40 #define MAXRTPPACKETSIN 32   // The number of max packets being reordered
41 
42 struct rtpbits {
43   unsigned int v:2;           /* version: 2 */
44   unsigned int p:1;           /* is there padding appended: 0 */
45   unsigned int x:1;           /* number of extension headers: 0 */
46   unsigned int cc:4;          /* number of CSRC identifiers: 0 */
47   unsigned int m:1;           /* marker: 0 */
48   unsigned int pt:7;          /* payload type: 33 for MPEG2 TS - RFC 1890 */
49   unsigned int sequence:16;   /* sequence number: random */
50 };
51 
52 struct rtpheader {	/* in network byte order */
53   struct rtpbits b;
54   int timestamp;	/* start: random */
55   int ssrc;		/* random */
56 };
57 
58 struct rtpbuffer
59 {
60 	unsigned char  data[MAXRTPPACKETSIN][STREAM_BUFFER_SIZE];
61 	unsigned short  seq[MAXRTPPACKETSIN];
62 	unsigned short  len[MAXRTPPACKETSIN];
63 	unsigned short first;
64 };
65 static struct rtpbuffer rtpbuf;
66 
67 static int getrtp2(int fd, struct rtpheader *rh, char** data, int* lengthData);
68 
69 // RTP Reordering functions
70 // Algorithm works as follows:
71 // If next packet is in sequence just copy it to buffer
72 // Otherwise copy it in cache according to its sequence number
73 // Cache is a circular array where "rtpbuf.first" points to next sequence slot
74 // and keeps track of expected sequence
75 
76 // Initialize rtp cache
rtp_cache_reset(unsigned short seq)77 static void rtp_cache_reset(unsigned short seq)
78 {
79 	int i;
80 
81 	rtpbuf.first = 0;
82 	rtpbuf.seq[0] = ++seq;
83 
84 	for (i=0; i<MAXRTPPACKETSIN; i++) {
85 		rtpbuf.len[i] = 0;
86 	}
87 }
88 
89 // Write in a cache the rtp packet in right rtp sequence order
rtp_cache(int fd,char * buffer,int length)90 static int rtp_cache(int fd, char *buffer, int length)
91 {
92 	struct rtpheader rh;
93 	int newseq;
94 	char *data;
95 	unsigned short seq;
96 	static int is_first = 1;
97 
98 	getrtp2(fd, &rh, &data, &length);
99 	if(!length)
100 		return 0;
101 	seq = rh.b.sequence;
102 
103 	newseq = seq - rtpbuf.seq[rtpbuf.first];
104 
105 	if ((newseq == 0) || is_first)
106 	{
107 		is_first = 0;
108 
109 		//mp_msg(MSGT_NETWORK, MSGL_DBG4, "RTP (seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq);
110 		rtpbuf.first = ( 1 + rtpbuf.first ) % MAXRTPPACKETSIN;
111 		rtpbuf.seq[rtpbuf.first] = ++seq;
112 		goto feed;
113 	}
114 
115 	if (newseq > MAXRTPPACKETSIN)
116 	{
117 		mp_msg(MSGT_NETWORK, MSGL_DBG2, "Overrun(seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq);
118 		rtp_cache_reset(seq);
119 		goto feed;
120 	}
121 
122 	if (newseq < 0)
123 	{
124 		int i;
125 
126 		// Is it a stray packet re-sent to network?
127 		for (i=0; i<MAXRTPPACKETSIN; i++) {
128 			if (rtpbuf.seq[i] == seq) {
129 				mp_msg(MSGT_NETWORK, MSGL_ERR, "Stray packet (seq[%d]=%d seq=%d, newseq=%d found at %d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq, i);
130 				return  0; // Yes, it is!
131 			}
132 		}
133 		// Some heuristic to decide when to drop packet or to restart everything
134 		if (newseq > -(3 * MAXRTPPACKETSIN)) {
135 			mp_msg(MSGT_NETWORK, MSGL_ERR, "Too Old packet (seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq);
136 			return  0; // Yes, it is!
137 		}
138 
139 		mp_msg(MSGT_NETWORK, MSGL_ERR,  "Underrun(seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq);
140 
141 		rtp_cache_reset(seq);
142 		goto feed;
143 	}
144 
145 	mp_msg(MSGT_NETWORK, MSGL_DBG4, "Out of Seq (seq[%d]=%d seq=%d, newseq=%d)\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first], seq, newseq);
146 	newseq = ( newseq + rtpbuf.first ) % MAXRTPPACKETSIN;
147 	memcpy (rtpbuf.data[newseq], data, length);
148 	rtpbuf.len[newseq] = length;
149 	rtpbuf.seq[newseq] = seq;
150 
151 	return 0;
152 
153 feed:
154 	memcpy (buffer, data, length);
155 	return length;
156 }
157 
158 // Get next packet in cache
159 // Look in cache to get first packet in sequence
rtp_get_next(int fd,char * buffer,int length)160 static int rtp_get_next(int fd, char *buffer, int length)
161 {
162 	int i;
163 	unsigned short nextseq;
164 
165 	// If we have empty buffer we loop to fill it
166 	for (i=0; i < MAXRTPPACKETSIN -3; i++) {
167 		if (rtpbuf.len[rtpbuf.first] != 0) break;
168 
169 		length = rtp_cache(fd, buffer, length) ;
170 
171 		// returns on first packet in sequence
172 		if (length > 0) {
173 			//mp_msg(MSGT_NETWORK, MSGL_DBG4, "Getting rtp [%d] %hu\n", i, rtpbuf.first);
174 			return length;
175 		} else if (length < 0) break;
176 
177 		// Only if length == 0 loop continues!
178 	}
179 
180 	i = rtpbuf.first;
181 	while (rtpbuf.len[i] == 0) {
182 		mp_msg(MSGT_NETWORK, MSGL_ERR,  "Lost packet %hu\n", rtpbuf.seq[i]);
183 		i = ( 1 + i ) % MAXRTPPACKETSIN;
184 		if (rtpbuf.first == i) break;
185 	}
186 	rtpbuf.first = i;
187 
188 	// Copy next non empty packet from cache
189 	mp_msg(MSGT_NETWORK, MSGL_DBG4, "Getting rtp from cache [%d] %hu\n", rtpbuf.first, rtpbuf.seq[rtpbuf.first]);
190 	memcpy (buffer, rtpbuf.data[rtpbuf.first], rtpbuf.len[rtpbuf.first]);
191 	length = rtpbuf.len[rtpbuf.first]; // can be zero?
192 
193 	// Reset fisrt slot and go next in cache
194 	rtpbuf.len[rtpbuf.first] = 0;
195 	nextseq = rtpbuf.seq[rtpbuf.first];
196 	rtpbuf.first = ( 1 + rtpbuf.first ) % MAXRTPPACKETSIN;
197 	rtpbuf.seq[rtpbuf.first] = nextseq + 1;
198 
199 	return length;
200 }
201 
202 
203 // Read next rtp packet using cache
read_rtp_from_server(int fd,char * buffer,int length)204 int read_rtp_from_server(int fd, char *buffer, int length) {
205 	// Following test is ASSERT (i.e. uneuseful if code is correct)
206 	if(buffer==NULL || length<STREAM_BUFFER_SIZE) {
207 		mp_msg(MSGT_NETWORK, MSGL_ERR, "RTP buffer invalid; no data return from network\n");
208 		return 0;
209 	}
210 
211 	// loop just to skip empty packets
212 	while ((length = rtp_get_next(fd, buffer, length)) == 0) {
213 		mp_msg(MSGT_NETWORK, MSGL_ERR, "Got empty packet from RTP cache!?\n");
214 	}
215 
216 	return length;
217 }
218 
getrtp2(int fd,struct rtpheader * rh,char ** data,int * lengthData)219 static int getrtp2(int fd, struct rtpheader *rh, char** data, int* lengthData) {
220   static char buf[1600];
221   unsigned int intP;
222   char* charP = (char*) &intP;
223   int headerSize;
224   int lengthPacket;
225   lengthPacket=recv(fd,buf,1590,0);
226   if (lengthPacket<0)
227     mp_msg(MSGT_NETWORK,MSGL_ERR,"rtp: socket read error\n");
228   else if (lengthPacket<12)
229     mp_msg(MSGT_NETWORK,MSGL_ERR,"rtp: packet too small (%d) to be an rtp frame (>12bytes)\n", lengthPacket);
230   if(lengthPacket<12) {
231     *lengthData = 0;
232     return 0;
233   }
234   rh->b.v  = (unsigned int) ((buf[0]>>6)&0x03);
235   rh->b.p  = (unsigned int) ((buf[0]>>5)&0x01);
236   rh->b.x  = (unsigned int) ((buf[0]>>4)&0x01);
237   rh->b.cc = (unsigned int) ((buf[0]>>0)&0x0f);
238   rh->b.m  = (unsigned int) ((buf[1]>>7)&0x01);
239   rh->b.pt = (unsigned int) ((buf[1]>>0)&0x7f);
240   intP = 0;
241   memcpy(charP+2,&buf[2],2);
242   rh->b.sequence = ntohl(intP);
243   intP = 0;
244   memcpy(charP,&buf[4],4);
245   rh->timestamp = ntohl(intP);
246 
247   headerSize = 12 + 4*rh->b.cc; /* in bytes */
248 
249   *lengthData = lengthPacket - headerSize;
250   *data = (char*) buf + headerSize;
251 
252   //  mp_msg(MSGT_NETWORK,MSGL_DBG2,"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);
253 
254   return 0;
255 }
256