annotate ffmpeg/libavformat/rdt.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * Realmedia RTSP protocol (RDT) support.
yading@11 3 * Copyright (c) 2007 Ronald S. Bultje
yading@11 4 *
yading@11 5 * This file is part of FFmpeg.
yading@11 6 *
yading@11 7 * FFmpeg is free software; you can redistribute it and/or
yading@11 8 * modify it under the terms of the GNU Lesser General Public
yading@11 9 * License as published by the Free Software Foundation; either
yading@11 10 * version 2.1 of the License, or (at your option) any later version.
yading@11 11 *
yading@11 12 * FFmpeg is distributed in the hope that it will be useful,
yading@11 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 15 * Lesser General Public License for more details.
yading@11 16 *
yading@11 17 * You should have received a copy of the GNU Lesser General Public
yading@11 18 * License along with FFmpeg; if not, write to the Free Software
yading@11 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 20 */
yading@11 21
yading@11 22 /**
yading@11 23 * @file
yading@11 24 * @brief Realmedia RTSP protocol (RDT) support
yading@11 25 * @author Ronald S. Bultje <rbultje@ronald.bitfreak.net>
yading@11 26 */
yading@11 27
yading@11 28 #include "avformat.h"
yading@11 29 #include "libavutil/avstring.h"
yading@11 30 #include "rtpdec.h"
yading@11 31 #include "rdt.h"
yading@11 32 #include "libavutil/base64.h"
yading@11 33 #include "libavutil/md5.h"
yading@11 34 #include "rm.h"
yading@11 35 #include "internal.h"
yading@11 36 #include "avio_internal.h"
yading@11 37 #include "libavcodec/get_bits.h"
yading@11 38
yading@11 39 struct RDTDemuxContext {
yading@11 40 AVFormatContext *ic; /**< the containing (RTSP) demux context */
yading@11 41 /** Each RDT stream-set (represented by one RTSPStream) can contain
yading@11 42 * multiple streams (of the same content, but with possibly different
yading@11 43 * codecs/bitrates). Each such stream is represented by one AVStream
yading@11 44 * in the AVFormatContext, and this variable points to the offset in
yading@11 45 * that array such that the first is the first stream of this set. */
yading@11 46 AVStream **streams;
yading@11 47 int n_streams; /**< streams with identifical content in this set */
yading@11 48 void *dynamic_protocol_context;
yading@11 49 DynamicPayloadPacketHandlerProc parse_packet;
yading@11 50 uint32_t prev_timestamp;
yading@11 51 int prev_set_id, prev_stream_id;
yading@11 52 };
yading@11 53
yading@11 54 RDTDemuxContext *
yading@11 55 ff_rdt_parse_open(AVFormatContext *ic, int first_stream_of_set_idx,
yading@11 56 void *priv_data, RTPDynamicProtocolHandler *handler)
yading@11 57 {
yading@11 58 RDTDemuxContext *s = av_mallocz(sizeof(RDTDemuxContext));
yading@11 59 if (!s)
yading@11 60 return NULL;
yading@11 61
yading@11 62 s->ic = ic;
yading@11 63 s->streams = &ic->streams[first_stream_of_set_idx];
yading@11 64 do {
yading@11 65 s->n_streams++;
yading@11 66 } while (first_stream_of_set_idx + s->n_streams < ic->nb_streams &&
yading@11 67 s->streams[s->n_streams]->id == s->streams[0]->id);
yading@11 68 s->prev_set_id = -1;
yading@11 69 s->prev_stream_id = -1;
yading@11 70 s->prev_timestamp = -1;
yading@11 71 s->parse_packet = handler ? handler->parse_packet : NULL;
yading@11 72 s->dynamic_protocol_context = priv_data;
yading@11 73
yading@11 74 return s;
yading@11 75 }
yading@11 76
yading@11 77 void
yading@11 78 ff_rdt_parse_close(RDTDemuxContext *s)
yading@11 79 {
yading@11 80 av_free(s);
yading@11 81 }
yading@11 82
yading@11 83 struct PayloadContext {
yading@11 84 AVFormatContext *rmctx;
yading@11 85 int nb_rmst;
yading@11 86 RMStream **rmst;
yading@11 87 uint8_t *mlti_data;
yading@11 88 unsigned int mlti_data_size;
yading@11 89 char buffer[RTP_MAX_PACKET_LENGTH + FF_INPUT_BUFFER_PADDING_SIZE];
yading@11 90 int audio_pkt_cnt; /**< remaining audio packets in rmdec */
yading@11 91 };
yading@11 92
yading@11 93 void
yading@11 94 ff_rdt_calc_response_and_checksum(char response[41], char chksum[9],
yading@11 95 const char *challenge)
yading@11 96 {
yading@11 97 int ch_len = strlen (challenge), i;
yading@11 98 unsigned char zres[16],
yading@11 99 buf[64] = { 0xa1, 0xe9, 0x14, 0x9d, 0x0e, 0x6b, 0x3b, 0x59 };
yading@11 100 #define XOR_TABLE_SIZE 37
yading@11 101 const unsigned char xor_table[XOR_TABLE_SIZE] = {
yading@11 102 0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
yading@11 103 0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
yading@11 104 0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
yading@11 105 0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
yading@11 106 0x10, 0x57, 0x05, 0x18, 0x54 };
yading@11 107
yading@11 108 /* some (length) checks */
yading@11 109 if (ch_len == 40) /* what a hack... */
yading@11 110 ch_len = 32;
yading@11 111 else if (ch_len > 56)
yading@11 112 ch_len = 56;
yading@11 113 memcpy(buf + 8, challenge, ch_len);
yading@11 114
yading@11 115 /* xor challenge bytewise with xor_table */
yading@11 116 for (i = 0; i < XOR_TABLE_SIZE; i++)
yading@11 117 buf[8 + i] ^= xor_table[i];
yading@11 118
yading@11 119 av_md5_sum(zres, buf, 64);
yading@11 120 ff_data_to_hex(response, zres, 16, 1);
yading@11 121
yading@11 122 /* add tail */
yading@11 123 strcpy (response + 32, "01d0a8e3");
yading@11 124
yading@11 125 /* calculate checksum */
yading@11 126 for (i = 0; i < 8; i++)
yading@11 127 chksum[i] = response[i * 4];
yading@11 128 chksum[8] = 0;
yading@11 129 }
yading@11 130
yading@11 131 static int
yading@11 132 rdt_load_mdpr (PayloadContext *rdt, AVStream *st, int rule_nr)
yading@11 133 {
yading@11 134 AVIOContext pb;
yading@11 135 int size;
yading@11 136 uint32_t tag;
yading@11 137
yading@11 138 /**
yading@11 139 * Layout of the MLTI chunk:
yading@11 140 * 4: MLTI
yading@11 141 * 2: number of streams
yading@11 142 * Then for each stream ([number_of_streams] times):
yading@11 143 * 2: mdpr index
yading@11 144 * 2: number of mdpr chunks
yading@11 145 * Then for each mdpr chunk ([number_of_mdpr_chunks] times):
yading@11 146 * 4: size
yading@11 147 * [size]: data
yading@11 148 * we skip MDPR chunks until we reach the one of the stream
yading@11 149 * we're interested in, and forward that ([size]+[data]) to
yading@11 150 * the RM demuxer to parse the stream-specific header data.
yading@11 151 */
yading@11 152 if (!rdt->mlti_data)
yading@11 153 return -1;
yading@11 154 ffio_init_context(&pb, rdt->mlti_data, rdt->mlti_data_size, 0,
yading@11 155 NULL, NULL, NULL, NULL);
yading@11 156 tag = avio_rl32(&pb);
yading@11 157 if (tag == MKTAG('M', 'L', 'T', 'I')) {
yading@11 158 int num, chunk_nr;
yading@11 159
yading@11 160 /* read index of MDPR chunk numbers */
yading@11 161 num = avio_rb16(&pb);
yading@11 162 if (rule_nr < 0 || rule_nr >= num)
yading@11 163 return -1;
yading@11 164 avio_skip(&pb, rule_nr * 2);
yading@11 165 chunk_nr = avio_rb16(&pb);
yading@11 166 avio_skip(&pb, (num - 1 - rule_nr) * 2);
yading@11 167
yading@11 168 /* read MDPR chunks */
yading@11 169 num = avio_rb16(&pb);
yading@11 170 if (chunk_nr >= num)
yading@11 171 return -1;
yading@11 172 while (chunk_nr--)
yading@11 173 avio_skip(&pb, avio_rb32(&pb));
yading@11 174 size = avio_rb32(&pb);
yading@11 175 } else {
yading@11 176 size = rdt->mlti_data_size;
yading@11 177 avio_seek(&pb, 0, SEEK_SET);
yading@11 178 }
yading@11 179 if (ff_rm_read_mdpr_codecdata(rdt->rmctx, &pb, st, rdt->rmst[st->index], size, NULL) < 0)
yading@11 180 return -1;
yading@11 181
yading@11 182 return 0;
yading@11 183 }
yading@11 184
yading@11 185 /**
yading@11 186 * Actual data handling.
yading@11 187 */
yading@11 188
yading@11 189 int
yading@11 190 ff_rdt_parse_header(const uint8_t *buf, int len,
yading@11 191 int *pset_id, int *pseq_no, int *pstream_id,
yading@11 192 int *pis_keyframe, uint32_t *ptimestamp)
yading@11 193 {
yading@11 194 GetBitContext gb;
yading@11 195 int consumed = 0, set_id, seq_no, stream_id, is_keyframe,
yading@11 196 len_included, need_reliable;
yading@11 197 uint32_t timestamp;
yading@11 198
yading@11 199 /* skip status packets */
yading@11 200 while (len >= 5 && buf[1] == 0xFF /* status packet */) {
yading@11 201 int pkt_len;
yading@11 202
yading@11 203 if (!(buf[0] & 0x80))
yading@11 204 return -1; /* not followed by a data packet */
yading@11 205
yading@11 206 pkt_len = AV_RB16(buf+3);
yading@11 207 buf += pkt_len;
yading@11 208 len -= pkt_len;
yading@11 209 consumed += pkt_len;
yading@11 210 }
yading@11 211 if (len < 16)
yading@11 212 return -1;
yading@11 213 /**
yading@11 214 * Layout of the header (in bits):
yading@11 215 * 1: len_included
yading@11 216 * Flag indicating whether this header includes a length field;
yading@11 217 * this can be used to concatenate multiple RDT packets in a
yading@11 218 * single UDP/TCP data frame and is used to precede RDT data
yading@11 219 * by stream status packets
yading@11 220 * 1: need_reliable
yading@11 221 * Flag indicating whether this header includes a "reliable
yading@11 222 * sequence number"; these are apparently sequence numbers of
yading@11 223 * data packets alone. For data packets, this flag is always
yading@11 224 * set, according to the Real documentation [1]
yading@11 225 * 5: set_id
yading@11 226 * ID of a set of streams of identical content, possibly with
yading@11 227 * different codecs or bitrates
yading@11 228 * 1: is_reliable
yading@11 229 * Flag set for certain streams deemed less tolerable for packet
yading@11 230 * loss
yading@11 231 * 16: seq_no
yading@11 232 * Packet sequence number; if >=0xFF00, this is a non-data packet
yading@11 233 * containing stream status info, the second byte indicates the
yading@11 234 * type of status packet (see wireshark docs / source code [2])
yading@11 235 * if (len_included) {
yading@11 236 * 16: packet_len
yading@11 237 * } else {
yading@11 238 * packet_len = remainder of UDP/TCP frame
yading@11 239 * }
yading@11 240 * 1: is_back_to_back
yading@11 241 * Back-to-Back flag; used for timing, set for one in every 10
yading@11 242 * packets, according to the Real documentation [1]
yading@11 243 * 1: is_slow_data
yading@11 244 * Slow-data flag; currently unused, according to Real docs [1]
yading@11 245 * 5: stream_id
yading@11 246 * ID of the stream within this particular set of streams
yading@11 247 * 1: is_no_keyframe
yading@11 248 * Non-keyframe flag (unset if packet belongs to a keyframe)
yading@11 249 * 32: timestamp (PTS)
yading@11 250 * if (set_id == 0x1F) {
yading@11 251 * 16: set_id (extended set-of-streams ID; see set_id)
yading@11 252 * }
yading@11 253 * if (need_reliable) {
yading@11 254 * 16: reliable_seq_no
yading@11 255 * Reliable sequence number (see need_reliable)
yading@11 256 * }
yading@11 257 * if (stream_id == 0x3F) {
yading@11 258 * 16: stream_id (extended stream ID; see stream_id)
yading@11 259 * }
yading@11 260 * [1] https://protocol.helixcommunity.org/files/2005/devdocs/RDT_Feature_Level_20.txt
yading@11 261 * [2] http://www.wireshark.org/docs/dfref/r/rdt.html and
yading@11 262 * http://anonsvn.wireshark.org/viewvc/trunk/epan/dissectors/packet-rdt.c
yading@11 263 */
yading@11 264 init_get_bits(&gb, buf, len << 3);
yading@11 265 len_included = get_bits1(&gb);
yading@11 266 need_reliable = get_bits1(&gb);
yading@11 267 set_id = get_bits(&gb, 5);
yading@11 268 skip_bits(&gb, 1);
yading@11 269 seq_no = get_bits(&gb, 16);
yading@11 270 if (len_included)
yading@11 271 skip_bits(&gb, 16);
yading@11 272 skip_bits(&gb, 2);
yading@11 273 stream_id = get_bits(&gb, 5);
yading@11 274 is_keyframe = !get_bits1(&gb);
yading@11 275 timestamp = get_bits_long(&gb, 32);
yading@11 276 if (set_id == 0x1f)
yading@11 277 set_id = get_bits(&gb, 16);
yading@11 278 if (need_reliable)
yading@11 279 skip_bits(&gb, 16);
yading@11 280 if (stream_id == 0x1f)
yading@11 281 stream_id = get_bits(&gb, 16);
yading@11 282
yading@11 283 if (pset_id) *pset_id = set_id;
yading@11 284 if (pseq_no) *pseq_no = seq_no;
yading@11 285 if (pstream_id) *pstream_id = stream_id;
yading@11 286 if (pis_keyframe) *pis_keyframe = is_keyframe;
yading@11 287 if (ptimestamp) *ptimestamp = timestamp;
yading@11 288
yading@11 289 return consumed + (get_bits_count(&gb) >> 3);
yading@11 290 }
yading@11 291
yading@11 292 /**< return 0 on packet, no more left, 1 on packet, 1 on partial packet... */
yading@11 293 static int
yading@11 294 rdt_parse_packet (AVFormatContext *ctx, PayloadContext *rdt, AVStream *st,
yading@11 295 AVPacket *pkt, uint32_t *timestamp,
yading@11 296 const uint8_t *buf, int len, uint16_t rtp_seq, int flags)
yading@11 297 {
yading@11 298 int seq = 1, res;
yading@11 299 AVIOContext pb;
yading@11 300
yading@11 301 if (rdt->audio_pkt_cnt == 0) {
yading@11 302 int pos;
yading@11 303
yading@11 304 ffio_init_context(&pb, buf, len, 0, NULL, NULL, NULL, NULL);
yading@11 305 flags = (flags & RTP_FLAG_KEY) ? 2 : 0;
yading@11 306 res = ff_rm_parse_packet (rdt->rmctx, &pb, st, rdt->rmst[st->index], len, pkt,
yading@11 307 &seq, flags, *timestamp);
yading@11 308 pos = avio_tell(&pb);
yading@11 309 if (res < 0)
yading@11 310 return res;
yading@11 311 if (res > 0) {
yading@11 312 if (st->codec->codec_id == AV_CODEC_ID_AAC) {
yading@11 313 memcpy (rdt->buffer, buf + pos, len - pos);
yading@11 314 rdt->rmctx->pb = avio_alloc_context (rdt->buffer, len - pos, 0,
yading@11 315 NULL, NULL, NULL, NULL);
yading@11 316 }
yading@11 317 goto get_cache;
yading@11 318 }
yading@11 319 } else {
yading@11 320 get_cache:
yading@11 321 rdt->audio_pkt_cnt =
yading@11 322 ff_rm_retrieve_cache (rdt->rmctx, rdt->rmctx->pb,
yading@11 323 st, rdt->rmst[st->index], pkt);
yading@11 324 if (rdt->audio_pkt_cnt == 0 &&
yading@11 325 st->codec->codec_id == AV_CODEC_ID_AAC)
yading@11 326 av_freep(&rdt->rmctx->pb);
yading@11 327 }
yading@11 328 pkt->stream_index = st->index;
yading@11 329 pkt->pts = *timestamp;
yading@11 330
yading@11 331 return rdt->audio_pkt_cnt > 0;
yading@11 332 }
yading@11 333
yading@11 334 int
yading@11 335 ff_rdt_parse_packet(RDTDemuxContext *s, AVPacket *pkt,
yading@11 336 uint8_t **bufptr, int len)
yading@11 337 {
yading@11 338 uint8_t *buf = bufptr ? *bufptr : NULL;
yading@11 339 int seq_no, flags = 0, stream_id, set_id, is_keyframe;
yading@11 340 uint32_t timestamp;
yading@11 341 int rv= 0;
yading@11 342
yading@11 343 if (!s->parse_packet)
yading@11 344 return -1;
yading@11 345
yading@11 346 if (!buf && s->prev_stream_id != -1) {
yading@11 347 /* return the next packets, if any */
yading@11 348 timestamp= 0; ///< Should not be used if buf is NULL, but should be set to the timestamp of the packet returned....
yading@11 349 rv= s->parse_packet(s->ic, s->dynamic_protocol_context,
yading@11 350 s->streams[s->prev_stream_id],
yading@11 351 pkt, &timestamp, NULL, 0, 0, flags);
yading@11 352 return rv;
yading@11 353 }
yading@11 354
yading@11 355 if (len < 12)
yading@11 356 return -1;
yading@11 357 rv = ff_rdt_parse_header(buf, len, &set_id, &seq_no, &stream_id, &is_keyframe, &timestamp);
yading@11 358 if (rv < 0)
yading@11 359 return rv;
yading@11 360 if (is_keyframe &&
yading@11 361 (set_id != s->prev_set_id || timestamp != s->prev_timestamp ||
yading@11 362 stream_id != s->prev_stream_id)) {
yading@11 363 flags |= RTP_FLAG_KEY;
yading@11 364 s->prev_set_id = set_id;
yading@11 365 s->prev_timestamp = timestamp;
yading@11 366 }
yading@11 367 s->prev_stream_id = stream_id;
yading@11 368 buf += rv;
yading@11 369 len -= rv;
yading@11 370
yading@11 371 if (s->prev_stream_id >= s->n_streams) {
yading@11 372 s->prev_stream_id = -1;
yading@11 373 return -1;
yading@11 374 }
yading@11 375
yading@11 376 rv = s->parse_packet(s->ic, s->dynamic_protocol_context,
yading@11 377 s->streams[s->prev_stream_id],
yading@11 378 pkt, &timestamp, buf, len, 0, flags);
yading@11 379
yading@11 380 return rv;
yading@11 381 }
yading@11 382
yading@11 383 void
yading@11 384 ff_rdt_subscribe_rule (char *cmd, int size,
yading@11 385 int stream_nr, int rule_nr)
yading@11 386 {
yading@11 387 av_strlcatf(cmd, size, "stream=%d;rule=%d,stream=%d;rule=%d",
yading@11 388 stream_nr, rule_nr * 2, stream_nr, rule_nr * 2 + 1);
yading@11 389 }
yading@11 390
yading@11 391 static unsigned char *
yading@11 392 rdt_parse_b64buf (unsigned int *target_len, const char *p)
yading@11 393 {
yading@11 394 unsigned char *target;
yading@11 395 int len = strlen(p);
yading@11 396 if (*p == '\"') {
yading@11 397 p++;
yading@11 398 len -= 2; /* skip embracing " at start/end */
yading@11 399 }
yading@11 400 *target_len = len * 3 / 4;
yading@11 401 target = av_mallocz(*target_len + FF_INPUT_BUFFER_PADDING_SIZE);
yading@11 402 av_base64_decode(target, p, *target_len);
yading@11 403 return target;
yading@11 404 }
yading@11 405
yading@11 406 static int
yading@11 407 rdt_parse_sdp_line (AVFormatContext *s, int st_index,
yading@11 408 PayloadContext *rdt, const char *line)
yading@11 409 {
yading@11 410 AVStream *stream = s->streams[st_index];
yading@11 411 const char *p = line;
yading@11 412
yading@11 413 if (av_strstart(p, "OpaqueData:buffer;", &p)) {
yading@11 414 rdt->mlti_data = rdt_parse_b64buf(&rdt->mlti_data_size, p);
yading@11 415 } else if (av_strstart(p, "StartTime:integer;", &p))
yading@11 416 stream->first_dts = atoi(p);
yading@11 417 else if (av_strstart(p, "ASMRuleBook:string;", &p)) {
yading@11 418 int n, first = -1;
yading@11 419
yading@11 420 for (n = 0; n < s->nb_streams; n++)
yading@11 421 if (s->streams[n]->id == stream->id) {
yading@11 422 int count = s->streams[n]->index + 1;
yading@11 423 if (first == -1) first = n;
yading@11 424 if (rdt->nb_rmst < count) {
yading@11 425 RMStream **rmst= av_realloc(rdt->rmst, count*sizeof(*rmst));
yading@11 426 if (!rmst)
yading@11 427 return AVERROR(ENOMEM);
yading@11 428 memset(rmst + rdt->nb_rmst, 0,
yading@11 429 (count - rdt->nb_rmst) * sizeof(*rmst));
yading@11 430 rdt->rmst = rmst;
yading@11 431 rdt->nb_rmst = count;
yading@11 432 }
yading@11 433 rdt->rmst[s->streams[n]->index] = ff_rm_alloc_rmstream();
yading@11 434 rdt_load_mdpr(rdt, s->streams[n], (n - first) * 2);
yading@11 435 }
yading@11 436 }
yading@11 437
yading@11 438 return 0;
yading@11 439 }
yading@11 440
yading@11 441 static void
yading@11 442 real_parse_asm_rule(AVStream *st, const char *p, const char *end)
yading@11 443 {
yading@11 444 do {
yading@11 445 /* can be either averagebandwidth= or AverageBandwidth= */
yading@11 446 if (sscanf(p, " %*1[Aa]verage%*1[Bb]andwidth=%d", &st->codec->bit_rate) == 1)
yading@11 447 break;
yading@11 448 if (!(p = strchr(p, ',')) || p > end)
yading@11 449 p = end;
yading@11 450 p++;
yading@11 451 } while (p < end);
yading@11 452 }
yading@11 453
yading@11 454 static AVStream *
yading@11 455 add_dstream(AVFormatContext *s, AVStream *orig_st)
yading@11 456 {
yading@11 457 AVStream *st;
yading@11 458
yading@11 459 if (!(st = avformat_new_stream(s, NULL)))
yading@11 460 return NULL;
yading@11 461 st->id = orig_st->id;
yading@11 462 st->codec->codec_type = orig_st->codec->codec_type;
yading@11 463 st->first_dts = orig_st->first_dts;
yading@11 464
yading@11 465 return st;
yading@11 466 }
yading@11 467
yading@11 468 static void
yading@11 469 real_parse_asm_rulebook(AVFormatContext *s, AVStream *orig_st,
yading@11 470 const char *p)
yading@11 471 {
yading@11 472 const char *end;
yading@11 473 int n_rules = 0, odd = 0;
yading@11 474 AVStream *st;
yading@11 475
yading@11 476 /**
yading@11 477 * The ASMRuleBook contains a list of comma-separated strings per rule,
yading@11 478 * and each rule is separated by a ;. The last one also has a ; at the
yading@11 479 * end so we can use it as delimiter.
yading@11 480 * Every rule occurs twice, once for when the RTSP packet header marker
yading@11 481 * is set and once for if it isn't. We only read the first because we
yading@11 482 * don't care much (that's what the "odd" variable is for).
yading@11 483 * Each rule contains a set of one or more statements, optionally
yading@11 484 * preceded by a single condition. If there's a condition, the rule
yading@11 485 * starts with a '#'. Multiple conditions are merged between brackets,
yading@11 486 * so there are never multiple conditions spread out over separate
yading@11 487 * statements. Generally, these conditions are bitrate limits (min/max)
yading@11 488 * for multi-bitrate streams.
yading@11 489 */
yading@11 490 if (*p == '\"') p++;
yading@11 491 while (1) {
yading@11 492 if (!(end = strchr(p, ';')))
yading@11 493 break;
yading@11 494 if (!odd && end != p) {
yading@11 495 if (n_rules > 0)
yading@11 496 st = add_dstream(s, orig_st);
yading@11 497 else
yading@11 498 st = orig_st;
yading@11 499 if (!st)
yading@11 500 break;
yading@11 501 real_parse_asm_rule(st, p, end);
yading@11 502 n_rules++;
yading@11 503 }
yading@11 504 p = end + 1;
yading@11 505 odd ^= 1;
yading@11 506 }
yading@11 507 }
yading@11 508
yading@11 509 void
yading@11 510 ff_real_parse_sdp_a_line (AVFormatContext *s, int stream_index,
yading@11 511 const char *line)
yading@11 512 {
yading@11 513 const char *p = line;
yading@11 514
yading@11 515 if (av_strstart(p, "ASMRuleBook:string;", &p))
yading@11 516 real_parse_asm_rulebook(s, s->streams[stream_index], p);
yading@11 517 }
yading@11 518
yading@11 519 static PayloadContext *
yading@11 520 rdt_new_context (void)
yading@11 521 {
yading@11 522 PayloadContext *rdt = av_mallocz(sizeof(PayloadContext));
yading@11 523
yading@11 524 int ret = avformat_open_input(&rdt->rmctx, "", &ff_rdt_demuxer, NULL);
yading@11 525 if (ret < 0) {
yading@11 526 av_free(rdt);
yading@11 527 return NULL;
yading@11 528 }
yading@11 529
yading@11 530 return rdt;
yading@11 531 }
yading@11 532
yading@11 533 static void
yading@11 534 rdt_free_context (PayloadContext *rdt)
yading@11 535 {
yading@11 536 int i;
yading@11 537
yading@11 538 for (i = 0; i < rdt->nb_rmst; i++)
yading@11 539 if (rdt->rmst[i]) {
yading@11 540 ff_rm_free_rmstream(rdt->rmst[i]);
yading@11 541 av_freep(&rdt->rmst[i]);
yading@11 542 }
yading@11 543 if (rdt->rmctx)
yading@11 544 avformat_close_input(&rdt->rmctx);
yading@11 545 av_freep(&rdt->mlti_data);
yading@11 546 av_freep(&rdt->rmst);
yading@11 547 av_free(rdt);
yading@11 548 }
yading@11 549
yading@11 550 #define RDT_HANDLER(n, s, t) \
yading@11 551 static RTPDynamicProtocolHandler ff_rdt_ ## n ## _handler = { \
yading@11 552 .enc_name = s, \
yading@11 553 .codec_type = t, \
yading@11 554 .codec_id = AV_CODEC_ID_NONE, \
yading@11 555 .parse_sdp_a_line = rdt_parse_sdp_line, \
yading@11 556 .alloc = rdt_new_context, \
yading@11 557 .free = rdt_free_context, \
yading@11 558 .parse_packet = rdt_parse_packet \
yading@11 559 }
yading@11 560
yading@11 561 RDT_HANDLER(live_video, "x-pn-multirate-realvideo-live", AVMEDIA_TYPE_VIDEO);
yading@11 562 RDT_HANDLER(live_audio, "x-pn-multirate-realaudio-live", AVMEDIA_TYPE_AUDIO);
yading@11 563 RDT_HANDLER(video, "x-pn-realvideo", AVMEDIA_TYPE_VIDEO);
yading@11 564 RDT_HANDLER(audio, "x-pn-realaudio", AVMEDIA_TYPE_AUDIO);
yading@11 565
yading@11 566 void av_register_rdt_dynamic_payload_handlers(void)
yading@11 567 {
yading@11 568 ff_register_dynamic_payload_handler(&ff_rdt_video_handler);
yading@11 569 ff_register_dynamic_payload_handler(&ff_rdt_audio_handler);
yading@11 570 ff_register_dynamic_payload_handler(&ff_rdt_live_video_handler);
yading@11 571 ff_register_dynamic_payload_handler(&ff_rdt_live_audio_handler);
yading@11 572 }