Statistics
| Branch: | Revision:

ffmpeg / libavformat / rdt.c @ e731b8d8

History | View | Annotate | Download (18.1 KB)

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