Statistics
| Branch: | Revision:

ffmpeg / libavformat / rdt.c @ 886e89d0

History | View | Annotate | Download (14.7 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
    RMStream *rmst[MAX_STREAMS];
85
    uint8_t *mlti_data;
86
    unsigned int mlti_data_size;
87
    char buffer[RTP_MAX_PACKET_LENGTH + FF_INPUT_BUFFER_PADDING_SIZE];
88
    int audio_pkt_cnt[MAX_STREAMS]; /**< remaining audio packets in rmdec */
89
};
90

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

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

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

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

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

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

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

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

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

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

    
181
    return 0;
182
}
183

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
374
    return rv;
375
}
376

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

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

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

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

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

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

    
421
    return 0;
422
}
423

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

    
429
    av_open_input_stream(&rdt->rmctx, NULL, "", &rdt_demuxer, NULL);
430
    rdt->rmst[0] = ff_rm_alloc_rmstream();
431

    
432
    return rdt;
433
}
434

    
435
static void
436
rdt_free_extradata (PayloadContext *rdt)
437
{
438
    ff_rm_free_rmstream(rdt->rmst[0]);
439
    if (rdt->rmctx)
440
        av_close_input_stream(rdt->rmctx);
441
    av_freep(&rdt->mlti_data);
442
    av_free(rdt);
443
}
444

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

    
456
RDT_HANDLER(live_video, "x-pn-multirate-realvideo-live", CODEC_TYPE_VIDEO);
457
RDT_HANDLER(live_audio, "x-pn-multirate-realaudio-live", CODEC_TYPE_AUDIO);
458
RDT_HANDLER(video,      "x-pn-realvideo",                CODEC_TYPE_VIDEO);
459
RDT_HANDLER(audio,      "x-pn-realaudio",                CODEC_TYPE_AUDIO);
460

    
461
void av_register_rdt_dynamic_payload_handlers(void)
462
{
463
    ff_register_dynamic_payload_handler(&ff_rdt_video_handler);
464
    ff_register_dynamic_payload_handler(&ff_rdt_audio_handler);
465
    ff_register_dynamic_payload_handler(&ff_rdt_live_video_handler);
466
    ff_register_dynamic_payload_handler(&ff_rdt_live_audio_handler);
467
}