Statistics
| Branch: | Revision:

ffmpeg / libavformat / rdt.c @ d7fb5a18

History | View | Annotate | Download (14.6 KB)

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 rdt.c
24
 * @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
#include "rtp_internal.h"
31
#include "rdt.h"
32
#include "libavutil/base64.h"
33
#include "libavutil/md5.h"
34
#include "rm.h"
35
#include "internal.h"
36
#include <libavcodec/bitstream.h>
37

    
38
struct RDTDemuxContext {
39
    AVFormatContext *ic; /**< the containing (RTSP) demux context */
40
    /** Each RDT stream-set (represented by one RTSPStream) can contain
41
     * multiple streams (of the same content, but with possibly different
42
     * codecs/bitrates). Each such stream is represented by one AVStream
43
     * in the AVFormatContext, and this variable points to the offset in
44
     * that array such that the first is the first stream of this set. */
45
    AVStream **streams;
46
    int n_streams; /**< streams with identifical content in this set */
47
    void *dynamic_protocol_context;
48
    DynamicPayloadPacketHandlerProc parse_packet;
49
    uint32_t prev_timestamp;
50
    int prev_set_id, prev_stream_id;
51
};
52

    
53
RDTDemuxContext *
54
ff_rdt_parse_open(AVFormatContext *ic, int first_stream_of_set_idx,
55
                  void *priv_data, RTPDynamicProtocolHandler *handler)
56
{
57
    RDTDemuxContext *s = av_mallocz(sizeof(RDTDemuxContext));
58
    if (!s)
59
        return NULL;
60

    
61
    s->ic = ic;
62
    s->streams = &ic->streams[first_stream_of_set_idx];
63
    do {
64
        s->n_streams++;
65
    } while (first_stream_of_set_idx + s->n_streams < ic->nb_streams &&
66
             s->streams[s->n_streams]->priv_data == s->streams[0]->priv_data);
67
    s->prev_set_id    = -1;
68
    s->prev_stream_id = -1;
69
    s->prev_timestamp = -1;
70
    s->parse_packet = handler->parse_packet;
71
    s->dynamic_protocol_context = priv_data;
72

    
73
    return s;
74
}
75

    
76
void
77
ff_rdt_parse_close(RDTDemuxContext *s)
78
{
79
    av_free(s);
80
}
81

    
82
struct PayloadContext {
83
    AVFormatContext *rmctx;
84
    uint8_t *mlti_data;
85
    unsigned int mlti_data_size;
86
    char buffer[RTP_MAX_PACKET_LENGTH + FF_INPUT_BUFFER_PADDING_SIZE];
87
    int audio_pkt_cnt[MAX_STREAMS]; /**< remaining audio packets in rmdec */
88
};
89

    
90
void
91
ff_rdt_calc_response_and_checksum(char response[41], char chksum[9],
92
                                  const char *challenge)
93
{
94
    int ch_len = strlen (challenge), i;
95
    unsigned char zres[16],
96
        buf[64] = { 0xa1, 0xe9, 0x14, 0x9d, 0x0e, 0x6b, 0x3b, 0x59 };
97
#define XOR_TABLE_SIZE 37
98
    const unsigned char xor_table[XOR_TABLE_SIZE] = {
99
        0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
100
        0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
101
        0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
102
        0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
103
        0x10, 0x57, 0x05, 0x18, 0x54 };
104

    
105
    /* some (length) checks */
106
    if (ch_len == 40) /* what a hack... */
107
        ch_len = 32;
108
    else if (ch_len > 56)
109
        ch_len = 56;
110
    memcpy(buf + 8, challenge, ch_len);
111

    
112
    /* xor challenge bytewise with xor_table */
113
    for (i = 0; i < XOR_TABLE_SIZE; i++)
114
        buf[8 + i] ^= xor_table[i];
115

    
116
    av_md5_sum(zres, buf, 64);
117
    ff_data_to_hex(response, zres, 16);
118
    for (i=0;i<32;i++) response[i] = tolower(response[i]);
119

    
120
    /* add tail */
121
    strcpy (response + 32, "01d0a8e3");
122

    
123
    /* calculate checksum */
124
    for (i = 0; i < 8; i++)
125
        chksum[i] = response[i * 4];
126
    chksum[8] = 0;
127
}
128

    
129
static int
130
rdt_load_mdpr (PayloadContext *rdt, AVStream *st, int rule_nr)
131
{
132
    ByteIOContext pb;
133
    int size;
134
    uint32_t tag;
135

    
136
    /**
137
     * Layout of the MLTI chunk:
138
     * 4:MLTI
139
     * 2:<number of streams>
140
     * Then for each stream ([number_of_streams] times):
141
     *     2:<mdpr index>
142
     * 2:<number of mdpr chunks>
143
     * Then for each mdpr chunk ([number_of_mdpr_chunks] times):
144
     *     4:<size>
145
     *     [size]:<data>
146
     * we skip MDPR chunks until we reach the one of the stream
147
     * we're interested in, and forward that ([size]+[data]) to
148
     * the RM demuxer to parse the stream-specific header data.
149
     */
150
    if (!rdt->mlti_data)
151
        return -1;
152
    init_put_byte(&pb, rdt->mlti_data, rdt->mlti_data_size, 0,
153
                  NULL, NULL, NULL, NULL);
154
    tag = get_le32(&pb);
155
    if (tag == MKTAG('M', 'L', 'T', 'I')) {
156
        int num, chunk_nr;
157

    
158
        /* read index of MDPR chunk numbers */
159
        num = get_be16(&pb);
160
        if (rule_nr < 0 || rule_nr >= num)
161
            return -1;
162
        url_fskip(&pb, rule_nr * 2);
163
        chunk_nr = get_be16(&pb);
164
        url_fskip(&pb, (num - 1 - rule_nr) * 2);
165

    
166
        /* read MDPR chunks */
167
        num = get_be16(&pb);
168
        if (chunk_nr >= num)
169
            return -1;
170
        while (chunk_nr--)
171
            url_fskip(&pb, get_be32(&pb));
172
        size = get_be32(&pb);
173
    } else {
174
        size = rdt->mlti_data_size;
175
        url_fseek(&pb, 0, SEEK_SET);
176
    }
177
    if (ff_rm_read_mdpr_codecdata(rdt->rmctx, &pb, st, size) < 0)
178
        return -1;
179

    
180
    return 0;
181
}
182

    
183
/**
184
 * Actual data handling.
185
 */
186

    
187
int
188
ff_rdt_parse_header(const uint8_t *buf, int len,
189
                    int *pset_id, int *pseq_no, int *pstream_id,
190
                    int *pis_keyframe, uint32_t *ptimestamp)
191
{
192
    GetBitContext gb;
193
    int consumed = 0, set_id, seq_no, stream_id, is_keyframe,
194
        len_included, need_reliable;
195
    uint32_t timestamp;
196

    
197
    /* skip status packets */
198
    while (len >= 5 && buf[1] == 0xFF /* status packet */) {
199
        int pkt_len;
200

    
201
        if (!(buf[0] & 0x80))
202
            return -1; /* not followed by a data packet */
203

    
204
        pkt_len = AV_RB16(buf+3);
205
        buf += pkt_len;
206
        len -= pkt_len;
207
        consumed += pkt_len;
208
    }
209
    if (len < 16)
210
        return -1;
211
    /**
212
     * Layout of the header (in bits):
213
     * 1:  len_included
214
     *     Flag indicating whether this header includes a length field;
215
     *     this can be used to concatenate multiple RDT packets in a
216
     *     single UDP/TCP data frame and is used to precede RDT data
217
     *     by stream status packets
218
     * 1:  need_reliable
219
     *     Flag indicating whether this header includes a "reliable
220
     *     sequence number"; these are apparently sequence numbers of
221
     *     data packets alone. For data packets, this flag is always
222
     *     set, according to the Real documentation [1]
223
     * 5:  set_id
224
     *     ID of a set of streams of identical content, possibly with
225
     *     different codecs or bitrates
226
     * 1:  is_reliable
227
     *     Flag set for certain streams deemed less tolerable for packet
228
     *     loss
229
     * 16: seq_no
230
     *     Packet sequence number; if >=0xFF00, this is a non-data packet
231
     *     containing stream status info, the second byte indicates the
232
     *     type of status packet (see wireshark docs / source code [2])
233
     * if (len_included) {
234
     *     16: packet_len
235
     * } else {
236
     *     packet_len = remainder of UDP/TCP frame
237
     * }
238
     * 1:  is_back_to_back
239
     *     Back-to-Back flag; used for timing, set for one in every 10
240
     *     packets, according to the Real documentation [1]
241
     * 1:  is_slow_data
242
     *     Slow-data flag; currently unused, according to Real docs [1]
243
     * 5:  stream_id
244
     *     ID of the stream within this particular set of streams
245
     * 1:  is_no_keyframe
246
     *     Non-keyframe flag (unset if packet belongs to a keyframe)
247
     * 32: timestamp (PTS)
248
     * if (set_id == 0x1F) {
249
     *     16: set_id (extended set-of-streams ID; see set_id)
250
     * }
251
     * if (need_reliable) {
252
     *     16: reliable_seq_no
253
     *         Reliable sequence number (see need_reliable)
254
     * }
255
     * if (stream_id == 0x3F) {
256
     *     16: stream_id (extended stream ID; see stream_id)
257
     * }
258
     * [1] https://protocol.helixcommunity.org/files/2005/devdocs/RDT_Feature_Level_20.txt
259
     * [2] http://www.wireshark.org/docs/dfref/r/rdt.html and
260
     *     http://anonsvn.wireshark.org/viewvc/trunk/epan/dissectors/packet-rdt.c
261
     */
262
    init_get_bits(&gb, buf, len << 3);
263
    len_included  = get_bits1(&gb);
264
    need_reliable = get_bits1(&gb);
265
    set_id        = get_bits(&gb, 5);
266
    skip_bits(&gb, 1);
267
    seq_no        = get_bits(&gb, 16);
268
    if (len_included)
269
        skip_bits(&gb, 16);
270
    skip_bits(&gb, 2);
271
    stream_id     = get_bits(&gb, 5);
272
    is_keyframe   = !get_bits1(&gb);
273
    timestamp     = get_bits_long(&gb, 32);
274
    if (set_id == 0x1f)
275
        set_id    = get_bits(&gb, 16);
276
    if (need_reliable)
277
        skip_bits(&gb, 16);
278
    if (stream_id == 0x1f)
279
        stream_id = get_bits(&gb, 16);
280

    
281
    if (pset_id)      *pset_id      = set_id;
282
    if (pseq_no)      *pseq_no      = seq_no;
283
    if (pstream_id)   *pstream_id   = stream_id;
284
    if (pis_keyframe) *pis_keyframe = is_keyframe;
285
    if (ptimestamp)   *ptimestamp   = timestamp;
286

    
287
    return consumed + (get_bits_count(&gb) >> 3);
288
}
289

    
290
/**< return 0 on packet, no more left, 1 on packet, 1 on partial packet... */
291
static int
292
rdt_parse_packet (PayloadContext *rdt, AVStream *st,
293
                  AVPacket *pkt, uint32_t *timestamp,
294
                  const uint8_t *buf, int len, int flags)
295
{
296
    int seq = 1, res;
297
    ByteIOContext pb;
298

    
299
    if (rdt->audio_pkt_cnt == 0) {
300
        int pos;
301

    
302
        init_put_byte(&pb, buf, len, 0, NULL, NULL, NULL, NULL);
303
        flags = (flags & PKT_FLAG_KEY) ? 2 : 0;
304
        res = ff_rm_parse_packet (rdt->rmctx, &pb, st, len, pkt,
305
                                  &seq, &flags, timestamp);
306
        pos = url_ftell(&pb);
307
        if (res < 0)
308
            return res;
309
        rdt->audio_pkt_cnt[st->id] = res;
310
        if (rdt->audio_pkt_cnt[st->id] > 0 &&
311
            st->codec->codec_id == CODEC_ID_AAC) {
312
            memcpy (rdt->buffer, buf + pos, len - pos);
313
            rdt->rmctx->pb = av_alloc_put_byte (rdt->buffer, len - pos, 0,
314
                                                NULL, NULL, NULL, NULL);
315
        }
316
    } else {
317
        ff_rm_retrieve_cache (rdt->rmctx, rdt->rmctx->pb, st, pkt);
318
        if (rdt->audio_pkt_cnt[st->id] == 0 &&
319
            st->codec->codec_id == CODEC_ID_AAC)
320
            av_freep(&rdt->rmctx->pb);
321
    }
322
    pkt->stream_index = st->index;
323
    pkt->pts = *timestamp;
324

    
325
    return rdt->audio_pkt_cnt[st->id] > 0;
326
}
327

    
328
int
329
ff_rdt_parse_packet(RDTDemuxContext *s, AVPacket *pkt,
330
                    const uint8_t *buf, int len)
331
{
332
    int seq_no, flags = 0, stream_id, set_id, is_keyframe;
333
    uint32_t timestamp;
334
    int rv= 0;
335

    
336
    if (!s->parse_packet)
337
        return -1;
338

    
339
    if (!buf && s->prev_stream_id != -1) {
340
        /* return the next packets, if any */
341
        timestamp= 0; ///< Should not be used if buf is NULL, but should be set to the timestamp of the packet returned....
342
        rv= s->parse_packet(s->dynamic_protocol_context,
343
                            s->streams[s->prev_stream_id],
344
                            pkt, &timestamp, NULL, 0, flags);
345
        return rv;
346
    }
347

    
348
    if (len < 12)
349
        return -1;
350
    rv = ff_rdt_parse_header(buf, len, &set_id, &seq_no, &stream_id, &is_keyframe, &timestamp);
351
    if (rv < 0)
352
        return rv;
353
    if (is_keyframe &&
354
        (set_id != s->prev_set_id || timestamp != s->prev_timestamp ||
355
         stream_id != s->prev_stream_id)) {
356
        flags |= PKT_FLAG_KEY;
357
        s->prev_set_id    = set_id;
358
        s->prev_timestamp = timestamp;
359
    }
360
    s->prev_stream_id = stream_id;
361
    buf += rv;
362
    len -= rv;
363

    
364
     if (s->prev_stream_id >= s->n_streams) {
365
         s->prev_stream_id = -1;
366
         return -1;
367
     }
368

    
369
    rv = s->parse_packet(s->dynamic_protocol_context,
370
                         s->streams[s->prev_stream_id],
371
                         pkt, &timestamp, buf, len, flags);
372

    
373
    return rv;
374
}
375

    
376
void
377
ff_rdt_subscribe_rule (char *cmd, int size,
378
                       int stream_nr, int rule_nr)
379
{
380
    av_strlcatf(cmd, size, "stream=%d;rule=%d,stream=%d;rule=%d",
381
                stream_nr, rule_nr * 2, stream_nr, rule_nr * 2 + 1);
382
}
383

    
384
void
385
ff_rdt_subscribe_rule2 (RDTDemuxContext *s, char *cmd, int size,
386
                        int stream_nr, int rule_nr)
387
{
388
    PayloadContext *rdt = s->dynamic_protocol_context;
389

    
390
    rdt_load_mdpr(rdt, s->streams[0], rule_nr * 2);
391
}
392

    
393
static unsigned char *
394
rdt_parse_b64buf (unsigned int *target_len, const char *p)
395
{
396
    unsigned char *target;
397
    int len = strlen(p);
398
    if (*p == '\"') {
399
        p++;
400
        len -= 2; /* skip embracing " at start/end */
401
    }
402
    *target_len = len * 3 / 4;
403
    target = av_mallocz(*target_len + FF_INPUT_BUFFER_PADDING_SIZE);
404
    av_base64_decode(target, p, *target_len);
405
    return target;
406
}
407

    
408
static int
409
rdt_parse_sdp_line (AVFormatContext *s, int st_index,
410
                    PayloadContext *rdt, const char *line)
411
{
412
    AVStream *stream = s->streams[st_index];
413
    const char *p = line;
414

    
415
    if (av_strstart(p, "OpaqueData:buffer;", &p)) {
416
        rdt->mlti_data = rdt_parse_b64buf(&rdt->mlti_data_size, p);
417
    } else if (av_strstart(p, "StartTime:integer;", &p))
418
        stream->first_dts = atoi(p);
419

    
420
    return 0;
421
}
422

    
423
static PayloadContext *
424
rdt_new_extradata (void)
425
{
426
    PayloadContext *rdt = av_mallocz(sizeof(PayloadContext));
427

    
428
    av_open_input_stream(&rdt->rmctx, NULL, "", &rdt_demuxer, NULL);
429

    
430
    return rdt;
431
}
432

    
433
static void
434
rdt_free_extradata (PayloadContext *rdt)
435
{
436
    if (rdt->rmctx)
437
        av_close_input_stream(rdt->rmctx);
438
    av_freep(&rdt->mlti_data);
439
    av_free(rdt);
440
}
441

    
442
#define RDT_HANDLER(n, s, t) \
443
static RTPDynamicProtocolHandler ff_rdt_ ## n ## _handler = { \
444
    s, \
445
    t, \
446
    CODEC_ID_NONE, \
447
    rdt_parse_sdp_line, \
448
    rdt_new_extradata, \
449
    rdt_free_extradata, \
450
    rdt_parse_packet \
451
};
452

    
453
RDT_HANDLER(live_video, "x-pn-multirate-realvideo-live", CODEC_TYPE_VIDEO);
454
RDT_HANDLER(live_audio, "x-pn-multirate-realaudio-live", CODEC_TYPE_AUDIO);
455
RDT_HANDLER(video,      "x-pn-realvideo",                CODEC_TYPE_VIDEO);
456
RDT_HANDLER(audio,      "x-pn-realaudio",                CODEC_TYPE_AUDIO);
457

    
458
void av_register_rdt_dynamic_payload_handlers(void)
459
{
460
    ff_register_dynamic_payload_handler(&ff_rdt_video_handler);
461
    ff_register_dynamic_payload_handler(&ff_rdt_audio_handler);
462
    ff_register_dynamic_payload_handler(&ff_rdt_live_video_handler);
463
    ff_register_dynamic_payload_handler(&ff_rdt_live_audio_handler);
464
}