1 /*
2 * Realmedia RTSP protocol (RDT) support.
3 * Copyright (c) 2007 Ronald S. Bultje
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /**
23 * @file
24 * @brief Realmedia RTSP protocol (RDT) support
25 * @author Ronald S. Bultje <rbultje@ronald.bitfreak.net>
26 */
27
39
42 /** Each RDT stream-set (represented by one RTSPStream) can contain
43 * multiple streams (of the same content, but with possibly different
44 * codecs/bitrates). Each such stream is represented by one AVStream
45 * in the AVFormatContext, and this variable points to the offset in
46 * that array such that the first is the first stream of this set. */
48 int n_streams;
/**< streams with identical content in this set */
53 };
54
58 {
62
64 s->streams = &ic->
streams[first_stream_of_set_idx];
65 do {
67 }
while (first_stream_of_set_idx +
s->n_streams < ic->
nb_streams &&
68 s->streams[
s->n_streams]->id ==
s->streams[0]->id);
70 s->prev_stream_id = -1;
71 s->prev_timestamp = -1;
73 s->dynamic_protocol_context = priv_data;
74
76 }
77
78 void
80 {
82 }
83
92 };
93
94 void
96 const char *challenge)
97 {
98 int ch_len = strlen (challenge),
i;
99 unsigned char zres[16],
100 buf[64] = { 0xa1, 0xe9, 0x14, 0x9d, 0x0e, 0x6b, 0x3b, 0x59 };
101 #define XOR_TABLE_SIZE 37
103 0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
104 0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
105 0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
106 0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
107 0x10, 0x57, 0x05, 0x18, 0x54 };
108
109 /* some (length) checks */
110 if (ch_len == 40) /* what a hack... */
111 ch_len = 32;
112 else if (ch_len > 56)
113 ch_len = 56;
114 memcpy(buf + 8, challenge, ch_len);
115
116 /* xor challenge bytewise with xor_table */
118 buf[8 +
i] ^= xor_table[
i];
119
122
123 /* add tail */
124 strcpy (response + 32, "01d0a8e3");
125
126 /* calculate checksum */
127 for (
i = 0;
i < 8;
i++)
128 chksum[
i] = response[
i * 4];
129 chksum[8] = 0;
130 }
131
132 static int
134 {
139
140 /**
141 * Layout of the MLTI chunk:
142 * 4: MLTI
143 * 2: number of streams
144 * Then for each stream ([number_of_streams] times):
145 * 2: mdpr index
146 * 2: number of mdpr chunks
147 * Then for each mdpr chunk ([number_of_mdpr_chunks] times):
148 * 4: size
149 * [size]: data
150 * we skip MDPR chunks until we reach the one of the stream
151 * we're interested in, and forward that ([size]+[data]) to
152 * the RM demuxer to parse the stream-specific header data.
153 */
155 return -1;
158 if (
tag ==
MKTAG(
'M',
'L',
'T',
'I')) {
159 int num, chunk_nr;
160
161 /* read index of MDPR chunk numbers */
163 if (rule_nr < 0 || rule_nr >= num)
164 return -1;
168
169 /* read MDPR chunks */
171 if (chunk_nr >= num)
172 return -1;
173 while (chunk_nr--)
176 } else {
179 }
181 return -1;
182
183 return 0;
184 }
185
186 /**
187 * Actual data handling.
188 */
189
190 int
192 int *pset_id, int *pseq_no, int *pstream_id,
193 int *pis_keyframe, uint32_t *ptimestamp)
194 {
196 int consumed = 0, set_id, seq_no, stream_id,
is_keyframe,
197 len_included, need_reliable;
198 uint32_t timestamp;
199
200 /* skip status packets */
201 while (
len >= 5 && buf[1] == 0xFF
/* status packet */) {
202 int pkt_len;
203
204 if (!(buf[0] & 0x80))
205 return -1; /* not followed by a data packet */
206
210 buf += pkt_len;
212 consumed += pkt_len;
213 }
215 return -1;
216 /**
217 * Layout of the header (in bits):
218 * 1: len_included
219 * Flag indicating whether this header includes a length field;
220 * this can be used to concatenate multiple RDT packets in a
221 * single UDP/TCP data frame and is used to precede RDT data
222 * by stream status packets
223 * 1: need_reliable
224 * Flag indicating whether this header includes a "reliable
225 * sequence number"; these are apparently sequence numbers of
226 * data packets alone. For data packets, this flag is always
227 * set, according to the Real documentation [1]
228 * 5: set_id
229 * ID of a set of streams of identical content, possibly with
230 * different codecs or bitrates
231 * 1: is_reliable
232 * Flag set for certain streams deemed less tolerable for packet
233 * loss
234 * 16: seq_no
235 * Packet sequence number; if >=0xFF00, this is a non-data packet
236 * containing stream status info, the second byte indicates the
237 * type of status packet (see wireshark docs / source code [2])
238 * if (len_included) {
239 * 16: packet_len
240 * } else {
241 * packet_len = remainder of UDP/TCP frame
242 * }
243 * 1: is_back_to_back
244 * Back-to-Back flag; used for timing, set for one in every 10
245 * packets, according to the Real documentation [1]
246 * 1: is_slow_data
247 * Slow-data flag; currently unused, according to Real docs [1]
248 * 5: stream_id
249 * ID of the stream within this particular set of streams
250 * 1: is_no_keyframe
251 * Non-keyframe flag (unset if packet belongs to a keyframe)
252 * 32: timestamp (PTS)
253 * if (set_id == 0x1F) {
254 * 16: set_id (extended set-of-streams ID; see set_id)
255 * }
256 * if (need_reliable) {
257 * 16: reliable_seq_no
258 * Reliable sequence number (see need_reliable)
259 * }
260 * if (stream_id == 0x3F) {
261 * 16: stream_id (extended stream ID; see stream_id)
262 * }
263 * [1] https://protocol.helixcommunity.org/files/2005/devdocs/RDT_Feature_Level_20.txt
264 * [2] http://www.wireshark.org/docs/dfref/r/rdt.html and
265 * http://anonsvn.wireshark.org/viewvc/trunk/epan/dissectors/packet-rdt.c
266 */
273 if (len_included)
279 if (set_id == 0x1f)
281 if (need_reliable)
283 if (stream_id == 0x1f)
285
286 if (pset_id) *pset_id = set_id;
287 if (pseq_no) *pseq_no = seq_no;
288 if (pstream_id) *pstream_id = stream_id;
290 if (ptimestamp) *ptimestamp = timestamp;
291
293 }
294
295 /**< return 0 on packet, no more left, 1 on packet, 1 on partial packet... */
296 static int
299 const uint8_t *buf,
int len, uint16_t rtp_seq,
int flags)
300 {
301 int seq = 1, res;
302
306
310 len,
pkt, &seq, rmflags, *timestamp);
312 if (res < 0)
313 return res;
314 if (res > 0) {
319 }
320 goto get_cache;
321 }
322 } else {
323 get_cache:
330 }
333
335 }
336
337 int
339 uint8_t **bufptr,
int len)
340 {
341 uint8_t *buf = bufptr ? *bufptr :
NULL;
343 uint32_t timestamp;
344 int rv= 0;
345
346 if (!
s->parse_packet)
347 return -1;
348
349 if (!buf &&
s->prev_stream_id != -1) {
350 /* return the next packets, if any */
351 timestamp= 0; ///< Should not be used if buf is NULL, but should be set to the timestamp of the packet returned....
352 rv=
s->parse_packet(
s->ic,
s->dynamic_protocol_context,
353 s->streams[
s->prev_stream_id],
355 return rv;
356 }
357
359 return -1;
361 if (rv < 0)
362 return rv;
364 (set_id !=
s->prev_set_id || timestamp !=
s->prev_timestamp ||
365 stream_id !=
s->prev_stream_id)) {
367 s->prev_set_id = set_id;
368 s->prev_timestamp = timestamp;
369 }
370 s->prev_stream_id = stream_id;
371 buf += rv;
373
374 if (
s->prev_stream_id >=
s->n_streams) {
375 s->prev_stream_id = -1;
376 return -1;
377 }
378
379 rv =
s->parse_packet(
s->ic,
s->dynamic_protocol_context,
380 s->streams[
s->prev_stream_id],
382
383 return rv;
384 }
385
386 void
388 int stream_nr, int rule_nr)
389 {
391 stream_nr, rule_nr * 2, stream_nr, rule_nr * 2 + 1);
392 }
393
394 static unsigned char *
396 {
397 unsigned char *target;
399 if (*p == '\"') {
400 p++;
401 len -= 2;
/* skip embracing " at start/end */
402 }
403 *target_len =
len * 3 / 4;
405 if (!target)
408 return target;
409 }
410
411 static int
414 {
416 const char *p =
line;
417
420 }
else if (
av_strstart(p,
"StartTime:integer;", &p))
422 else if (
av_strstart(p,
"ASMRuleBook:string;", &p)) {
424
425 for (n = 0; n <
s->nb_streams; n++)
426 if (
s->streams[n]->id == stream->
id) {
427 int count =
s->streams[n]->index + 1, err;
431 count *
sizeof(*rdt->
rmst))) < 0) {
433 return err;
434 }
438 }
440 if (!rdt->
rmst[
s->streams[n]->index])
443 }
444 }
445
446 return 0;
447 }
448
449 static void
451 {
452 do {
453 /* can be either averagebandwidth= or AverageBandwidth= */
454 if (sscanf(p,
" %*1[Aa]verage%*1[Bb]andwidth=%"SCNd64, &st->
codecpar->
bit_rate) == 1)
455 break;
456 if (!(p = strchr(p, ',')) || p > end)
457 p = end;
458 p++;
459 } while (p < end);
460 }
461
464 {
466
469 st->
id = orig_st->
id;
472
473 return st;
474 }
475
476 static void
478 const char *p)
479 {
480 const char *end;
481 int n_rules = 0, odd = 0;
483
484 /**
485 * The ASMRuleBook contains a list of comma-separated strings per rule,
486 * and each rule is separated by a ;. The last one also has a ; at the
487 * end so we can use it as delimiter.
488 * Every rule occurs twice, once for when the RTSP packet header marker
489 * is set and once for if it isn't. We only read the first because we
490 * don't care much (that's what the "odd" variable is for).
491 * Each rule contains a set of one or more statements, optionally
492 * preceded by a single condition. If there's a condition, the rule
493 * starts with a '#'. Multiple conditions are merged between brackets,
494 * so there are never multiple conditions spread out over separate
495 * statements. Generally, these conditions are bitrate limits (min/max)
496 * for multi-bitrate streams.
497 */
498 if (*p == '\"') p++;
499 while (1) {
500 if (!(end = strchr(p, ';')))
501 break;
502 if (!odd && end != p) {
503 if (n_rules > 0)
505 else
506 st = orig_st;
507 if (!st)
508 break;
510 n_rules++;
511 }
512 p = end + 1;
513 odd ^= 1;
514 }
515 }
516
517 void
520 {
521 const char *p =
line;
522
525 }
526
527
528
530 {
532
536
539
541 }
542
543 static void
545 {
547
552 }
557 }
558
559 #define RDT_HANDLER(n, s, t) \
560 const RTPDynamicProtocolHandler ff_rdt_ ## n ## _handler = { \
561 .enc_name = s, \
562 .codec_type = t, \
563 .codec_id = AV_CODEC_ID_NONE, \
564 .priv_data_size = sizeof(PayloadContext), \
565 .init = rdt_init, \
566 .parse_sdp_a_line = rdt_parse_sdp_line, \
567 .close = rdt_close_context, \
568 .parse_packet = rdt_parse_packet \
569 }
570
575