1 |
14 |
jamey.hick |
|
2 |
|
|
/*!
|
3 |
|
|
************************************************************************
|
4 |
|
|
* \file rtp.c
|
5 |
|
|
*
|
6 |
|
|
* \brief
|
7 |
|
|
* Network Adaptation layer for RTP packets
|
8 |
|
|
*
|
9 |
|
|
* \author
|
10 |
|
|
* Main contributors (see contributors.h for copyright, address and affiliation details)
|
11 |
|
|
* - Stephan Wenger <stewe@cs.tu-berlin.de>
|
12 |
|
|
************************************************************************
|
13 |
|
|
*/
|
14 |
|
|
|
15 |
|
|
|
16 |
|
|
/*!
|
17 |
|
|
|
18 |
|
|
A quick guide to the basics of the RTP decoder implementation
|
19 |
|
|
|
20 |
|
|
This module contains the RTP packetization, de-packetization, and the
|
21 |
|
|
handling of Parameter Sets, see VCEG-N52 and accompanying documents.
|
22 |
|
|
Note: Compound packets are not yet implemented!
|
23 |
|
|
|
24 |
|
|
The interface between every NAL (including the RTP NAL) and the VCL is
|
25 |
|
|
based on Slices. The slice data structure on which the VCL is working
|
26 |
|
|
is defined in the type Slice (in defines.h). This type contains the
|
27 |
|
|
various fields of the slice header and a partition array, which itself
|
28 |
|
|
contains the data partitions the slice consists of. When data
|
29 |
|
|
partitioning is not used, then the whole slice bit string is stored
|
30 |
|
|
in partition #0. When individual partitions are missing, this is
|
31 |
|
|
indicated by the size of the bit strings in the partition array.
|
32 |
|
|
A complete missing slice (e.g. if a Full Slice packet was lost) is
|
33 |
|
|
indicated in a similar way.
|
34 |
|
|
|
35 |
|
|
part of the slice structure is the error indication (ei-flag). The
|
36 |
|
|
Ei-flag is set in such cases in which at least one partition of a slice
|
37 |
|
|
is damaged or missing.When data partitioning is used, it can happen that
|
38 |
|
|
one partition does not contain any symbols but the ei_flag is cleared,
|
39 |
|
|
which indicates the intentional missing of symbols of that partition.
|
40 |
|
|
A typical example for this behaviour is the Intra Slice, which does not
|
41 |
|
|
have symnbols in its type C partition.
|
42 |
|
|
|
43 |
|
|
The VCL requests new data to work on through the call of readSliceRTP().
|
44 |
|
|
This function calls the main state machine of this module in ReadRTPpaacket().
|
45 |
|
|
|
46 |
|
|
ReadRTPpacket assumes, when called, that in an error free environment
|
47 |
|
|
a complete slice, consisting of one Full Slice RTP packet, or three Partition
|
48 |
|
|
packets of types A, B, C with consecutive sequence numbers, can be read.
|
49 |
|
|
It first interprets any trailing SUPP and Parameter Update (Header) packets.
|
50 |
|
|
Then it reads one video data packet. Two cases have to be distinguished:
|
51 |
|
|
|
52 |
|
|
1. Type A, or Full Slice packet
|
53 |
|
|
In this case, the PictureID and the macroblock mumbers are used to
|
54 |
|
|
identify the potential loss of a slice. A slice is lost, when the
|
55 |
|
|
StartMB of the newly read slice header is not equal to the current
|
56 |
|
|
state of the decoder
|
57 |
|
|
1.1 Loss detected
|
58 |
|
|
In this case the last packet is unread (fseek back), and a dummy slice
|
59 |
|
|
containing the missing macroblocks is conveyed to the VCL. At the next
|
60 |
|
|
call of the NAL, the same packet is read again, but this time no packet
|
61 |
|
|
loss is detected by the above algorithm,
|
62 |
|
|
1.2. No loss
|
63 |
|
|
In this case it is checked whether a Full Slice packet or a type A data
|
64 |
|
|
partition was read
|
65 |
|
|
1.2.1 Full Slice
|
66 |
|
|
The Full Slice packet is conveyed to the NAL
|
67 |
|
|
1.2.2 Type A Partition
|
68 |
|
|
The function RTPReadDataPartitionedSlice() is called, which collects
|
69 |
|
|
the remaining type B, C partitions and handles them appropriately.
|
70 |
|
|
|
71 |
|
|
Paraneter Update Packets (aka Header packets) are in an SDP-like syntax
|
72 |
|
|
and are interpreted by a simple parser in the function
|
73 |
|
|
RTPInterpretParameterSetPacket()
|
74 |
|
|
|
75 |
|
|
Each Slice header contaions the information on which parameter set to be used.
|
76 |
|
|
The function RTPSetImgInp() copies the information of the relevant parameter
|
77 |
|
|
set in the VCL's global variables img-> and inp-> IMPORTANT: any changes
|
78 |
|
|
in the semantics of the img-> and inp-> structure members must be represented
|
79 |
|
|
in this function as well!
|
80 |
|
|
|
81 |
|
|
A note to the stream-buffer data structure: The stream buffer always contains
|
82 |
|
|
only the contents of the partition in question, and not the slice/partition
|
83 |
|
|
header. Decoding has to start at bitoffset 0 (UVLC) or bytreoffset 0 (CABAC).
|
84 |
|
|
|
85 |
|
|
The remaining functions should be self-explanatory.
|
86 |
|
|
|
87 |
|
|
*/
|
88 |
|
|
|
89 |
|
|
#include "contributors.h"
|
90 |
|
|
|
91 |
|
|
#include <assert.h>
|
92 |
|
|
#include <stdlib.h>
|
93 |
|
|
#include <math.h>
|
94 |
|
|
#include <string.h>
|
95 |
|
|
#include <ctype.h>
|
96 |
|
|
|
97 |
|
|
#include "global.h"
|
98 |
|
|
#include "errorconcealment.h"
|
99 |
|
|
#include "rtp.h"
|
100 |
|
|
#include "fmo.h"
|
101 |
|
|
#include "sei.h"
|
102 |
|
|
#include "memalloc.h"
|
103 |
|
|
|
104 |
|
|
#ifdef WIN32
|
105 |
|
|
#include <Winsock2.h>
|
106 |
|
|
#else
|
107 |
|
|
#include <netinet/in.h>
|
108 |
|
|
#endif
|
109 |
|
|
|
110 |
|
|
FILE *bits;
|
111 |
|
|
|
112 |
|
|
int RTPReadPacket (RTPpacket_t *p, FILE *bits);
|
113 |
|
|
|
114 |
|
|
/*!
|
115 |
|
|
************************************************************************
|
116 |
|
|
* \brief
|
117 |
|
|
* Opens the bit stream file named fn
|
118 |
|
|
* \return
|
119 |
|
|
* none
|
120 |
|
|
************************************************************************
|
121 |
|
|
*/
|
122 |
|
|
void OpenRTPFile (char *fn)
|
123 |
|
|
{
|
124 |
|
|
if (NULL == (bits=fopen(fn, "rb")))
|
125 |
|
|
{
|
126 |
|
|
snprintf (errortext, ET_SIZE, "Cannot open RTP file '%s'", input->infile);
|
127 |
|
|
error(errortext,500);
|
128 |
|
|
}
|
129 |
|
|
}
|
130 |
|
|
|
131 |
|
|
|
132 |
|
|
/*!
|
133 |
|
|
************************************************************************
|
134 |
|
|
* \brief
|
135 |
|
|
* Closes the bit stream file
|
136 |
|
|
************************************************************************
|
137 |
|
|
*/
|
138 |
|
|
void CloseRTPFile()
|
139 |
|
|
{
|
140 |
|
|
fclose (bits);
|
141 |
|
|
}
|
142 |
|
|
|
143 |
|
|
|
144 |
|
|
/*!
|
145 |
|
|
************************************************************************
|
146 |
|
|
* \brief
|
147 |
|
|
* Fills nalu->buf and nalu->len with the payload of an RTP packet.
|
148 |
|
|
* Other fields in nalu-> remain uninitialized (will be taken care of
|
149 |
|
|
* by NALUtoRBSP.
|
150 |
|
|
*
|
151 |
|
|
* \return
|
152 |
|
|
* 4 in case of ok (for compatibility with GetAnnexbNALU)
|
153 |
|
|
* 0 if there is nothing any more to read (EOF)
|
154 |
|
|
* -1 in case of any error
|
155 |
|
|
*
|
156 |
|
|
************************************************************************
|
157 |
|
|
*/
|
158 |
|
|
|
159 |
|
|
int GetRTPNALU (NALU_t *nalu)
|
160 |
|
|
{
|
161 |
|
|
RTPpacket_t *p;
|
162 |
|
|
int ret;
|
163 |
|
|
|
164 |
|
|
if ((p=malloc (sizeof (RTPpacket_t)))== NULL)
|
165 |
|
|
no_mem_exit ("GetRTPNALU-1");
|
166 |
|
|
if ((p->packet=malloc (MAXRTPPACKETSIZE))== NULL)
|
167 |
|
|
no_mem_exit ("GetRTPNALU-2");
|
168 |
|
|
if ((p->payload=malloc (MAXRTPPACKETSIZE))== NULL)
|
169 |
|
|
no_mem_exit ("GetRTPNALU-3");
|
170 |
|
|
|
171 |
|
|
ret = RTPReadPacket (p, bits);
|
172 |
|
|
nalu->forbidden_bit = 1;
|
173 |
|
|
nalu->len = 0;
|
174 |
|
|
|
175 |
|
|
if (ret < 0)
|
176 |
|
|
return -1;
|
177 |
|
|
if (ret == 0)
|
178 |
|
|
return 0;
|
179 |
|
|
|
180 |
|
|
assert (p->paylen < nalu->max_size);
|
181 |
|
|
|
182 |
|
|
nalu->len = p->paylen;
|
183 |
|
|
memcpy (nalu->buf, p->payload, p->paylen);
|
184 |
|
|
nalu->forbidden_bit = (nalu->buf[0]>>7) & 1;
|
185 |
|
|
nalu->nal_reference_idc = (nalu->buf[0]>>5) & 3;
|
186 |
|
|
nalu->nal_unit_type = (nalu->buf[0]) & 0x1f;
|
187 |
|
|
|
188 |
|
|
free (p->payload);
|
189 |
|
|
free (p->packet);
|
190 |
|
|
free (p);
|
191 |
|
|
// printf ("Got an RTP NALU, len %d, first byte %x\n", nalu->len, nalu->buf[0]);
|
192 |
|
|
return nalu->len;
|
193 |
|
|
}
|
194 |
|
|
|
195 |
|
|
|
196 |
|
|
|
197 |
|
|
/*!
|
198 |
|
|
*****************************************************************************
|
199 |
|
|
*
|
200 |
|
|
* \brief
|
201 |
|
|
* DecomposeRTPpacket interprets the RTP packet and writes the various
|
202 |
|
|
* structure members of the RTPpacket_t structure
|
203 |
|
|
*
|
204 |
|
|
* \return
|
205 |
|
|
* 0 in case of success
|
206 |
|
|
* negative error code in case of failure
|
207 |
|
|
*
|
208 |
|
|
* \param p
|
209 |
|
|
* Caller is responsible to allocate enough memory for the generated payload
|
210 |
|
|
* in parameter->payload. Typically a malloc of paclen-12 bytes is sufficient
|
211 |
|
|
*
|
212 |
|
|
* \par Side effects
|
213 |
|
|
* none
|
214 |
|
|
*
|
215 |
|
|
* \date
|
216 |
|
|
* 30 Spetember 2001
|
217 |
|
|
*
|
218 |
|
|
* \author
|
219 |
|
|
* Stephan Wenger stewe@cs.tu-berlin.de
|
220 |
|
|
*****************************************************************************/
|
221 |
|
|
|
222 |
|
|
int DecomposeRTPpacket (RTPpacket_t *p)
|
223 |
|
|
|
224 |
|
|
{
|
225 |
|
|
// consistency check
|
226 |
|
|
assert (p->packlen < 65536 - 28); // IP, UDP headers
|
227 |
|
|
assert (p->packlen >= 12); // at least a complete RTP header
|
228 |
|
|
assert (p->payload != NULL);
|
229 |
|
|
assert (p->packet != NULL);
|
230 |
|
|
|
231 |
|
|
// Extract header information
|
232 |
|
|
|
233 |
|
|
p->v = (p->packet[0] >> 6) & 0x03;
|
234 |
|
|
p->p = (p->packet[0] >> 5) & 0x01;
|
235 |
|
|
p->x = (p->packet[0] >> 4) & 0x01;
|
236 |
|
|
p->cc = (p->packet[0] >> 0) & 0x0F;
|
237 |
|
|
|
238 |
|
|
p->m = (p->packet[1] >> 7) & 0x01;
|
239 |
|
|
p->pt = (p->packet[1] >> 0) & 0x7F;
|
240 |
|
|
|
241 |
|
|
memcpy (&p->seq, &p->packet[2], 2);
|
242 |
|
|
p->seq = ntohs((unsigned short)p->seq);
|
243 |
|
|
|
244 |
|
|
memcpy (&p->timestamp, &p->packet[4], 4);// change to shifts for unified byte sex
|
245 |
|
|
p->timestamp = ntohl(p->timestamp);
|
246 |
|
|
memcpy (&p->ssrc, &p->packet[8], 4);// change to shifts for unified byte sex
|
247 |
|
|
p->ssrc = ntohl(p->ssrc);
|
248 |
|
|
|
249 |
|
|
// header consistency checks
|
250 |
|
|
if ( (p->v != 2)
|
251 |
|
|
|| (p->p != 0)
|
252 |
|
|
|| (p->x != 0)
|
253 |
|
|
|| (p->cc != 0) )
|
254 |
|
|
{
|
255 |
|
|
printf ("DecomposeRTPpacket, RTP header consistency problem, header follows\n");
|
256 |
|
|
DumpRTPHeader (p);
|
257 |
|
|
return -1;
|
258 |
|
|
}
|
259 |
|
|
p->paylen = p->packlen-12;
|
260 |
|
|
memcpy (p->payload, &p->packet[12], p->paylen);
|
261 |
|
|
return 0;
|
262 |
|
|
}
|
263 |
|
|
|
264 |
|
|
/*!
|
265 |
|
|
*****************************************************************************
|
266 |
|
|
*
|
267 |
|
|
* \brief
|
268 |
|
|
* DumpRTPHeader is a debug tool that dumps a human-readable interpretation
|
269 |
|
|
* of the RTP header
|
270 |
|
|
*
|
271 |
|
|
* \return
|
272 |
|
|
* n.a.
|
273 |
|
|
* \param p
|
274 |
|
|
* the RTP packet to be dumped, after DecompositeRTPpacket()
|
275 |
|
|
*
|
276 |
|
|
* \par Side effects
|
277 |
|
|
* Debug output to stdout
|
278 |
|
|
*
|
279 |
|
|
* \date
|
280 |
|
|
* 30 Spetember 2001
|
281 |
|
|
*
|
282 |
|
|
* \author
|
283 |
|
|
* Stephan Wenger stewe@cs.tu-berlin.de
|
284 |
|
|
*****************************************************************************/
|
285 |
|
|
|
286 |
|
|
void DumpRTPHeader (RTPpacket_t *p)
|
287 |
|
|
|
288 |
|
|
{
|
289 |
|
|
int i;
|
290 |
|
|
for (i=0; i< 30; i++)
|
291 |
|
|
printf ("%02x ", p->packet[i]);
|
292 |
|
|
printf ("Version (V): %d\n", p->v);
|
293 |
|
|
printf ("Padding (P): %d\n", p->p);
|
294 |
|
|
printf ("Extension (X): %d\n", p->x);
|
295 |
|
|
printf ("CSRC count (CC): %d\n", p->cc);
|
296 |
|
|
printf ("Marker bit (M): %d\n", p->m);
|
297 |
|
|
printf ("Payload Type (PT): %d\n", p->pt);
|
298 |
|
|
printf ("Sequence Number: %d\n", p->seq);
|
299 |
|
|
printf ("Timestamp: %d\n", p->timestamp);
|
300 |
|
|
printf ("SSRC: %d\n", p->ssrc);
|
301 |
|
|
}
|
302 |
|
|
|
303 |
|
|
|
304 |
|
|
/*!
|
305 |
|
|
*****************************************************************************
|
306 |
|
|
*
|
307 |
|
|
* \brief
|
308 |
|
|
* RTPReadPacket reads one packet from file
|
309 |
|
|
*
|
310 |
|
|
* \return
|
311 |
|
|
* 0: EOF
|
312 |
|
|
* negative: error
|
313 |
|
|
* positive: size of RTP packet in bytes
|
314 |
|
|
*
|
315 |
|
|
* \param p
|
316 |
|
|
* packet data structure, with memory for p->packet allocated
|
317 |
|
|
*
|
318 |
|
|
* \param bits
|
319 |
|
|
* target file
|
320 |
|
|
*
|
321 |
|
|
* \par Side effects:
|
322 |
|
|
* - File pointer in bits moved
|
323 |
|
|
* - p->xxx filled by reading and Decomposepacket()
|
324 |
|
|
*
|
325 |
|
|
* \date
|
326 |
|
|
* 04 November, 2001
|
327 |
|
|
*
|
328 |
|
|
* \author
|
329 |
|
|
* Stephan Wenger, stewe@cs.tu-berlin.de
|
330 |
|
|
*****************************************************************************/
|
331 |
|
|
|
332 |
|
|
int RTPReadPacket (RTPpacket_t *p, FILE *bits)
|
333 |
|
|
{
|
334 |
|
|
int Filepos, intime;
|
335 |
|
|
|
336 |
|
|
assert (p != NULL);
|
337 |
|
|
assert (p->packet != NULL);
|
338 |
|
|
assert (p->payload != NULL);
|
339 |
|
|
|
340 |
|
|
Filepos = ftell (bits);
|
341 |
|
|
if (4 != fread (&p->packlen,1, 4, bits))
|
342 |
|
|
{
|
343 |
|
|
return 0;
|
344 |
|
|
}
|
345 |
|
|
|
346 |
|
|
if (4 != fread (&intime, 1, 4, bits))
|
347 |
|
|
{
|
348 |
|
|
fseek (bits, Filepos, SEEK_SET);
|
349 |
|
|
printf ("RTPReadPacket: File corruption, could not read Timestamp, exit\n");
|
350 |
|
|
exit (-1);
|
351 |
|
|
}
|
352 |
|
|
|
353 |
|
|
assert (p->packlen < MAXRTPPACKETSIZE);
|
354 |
|
|
|
355 |
|
|
if (p->packlen != fread (p->packet, 1, p->packlen, bits))
|
356 |
|
|
{
|
357 |
|
|
printf ("RTPReadPacket: File corruption, could not read %d bytes\n", p->packlen);
|
358 |
|
|
exit (-1); // EOF inidication
|
359 |
|
|
}
|
360 |
|
|
|
361 |
|
|
if (DecomposeRTPpacket (p) < 0)
|
362 |
|
|
{
|
363 |
|
|
// this should never happen, hence exit() is ok. We probably do not want to attempt
|
364 |
|
|
// to decode a packet that obviously wasn't generated by RTP
|
365 |
|
|
printf ("Errors reported by DecomposePacket(), exit\n");
|
366 |
|
|
exit (-700);
|
367 |
|
|
}
|
368 |
|
|
assert (p->pt == H264PAYLOADTYPE);
|
369 |
|
|
assert (p->ssrc == H264SSRC);
|
370 |
|
|
return p->packlen;
|
371 |
|
|
}
|
372 |
|
|
|