Statistics
| Branch: | Revision:

ffmpeg / libavformat / rtsp.c @ 438fcb75

History | View | Annotate | Download (34.4 KB)

1
/*
2
 * RTSP/SDP client
3
 * Copyright (c) 2002 Fabrice Bellard.
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 */
19
#include "avformat.h"
20

    
21
#include <unistd.h> /* for select() prototype */
22
#include <sys/time.h>
23
#include <netinet/in.h>
24
#include <sys/socket.h>
25
#include <ctype.h>
26
#ifndef __BEOS__
27
# include <arpa/inet.h>
28
#else
29
# include "barpainet.h"
30
#endif
31

    
32
//#define DEBUG
33
//#define DEBUG_RTP_TCP
34

    
35
typedef struct RTSPState {
36
    URLContext *rtsp_hd; /* RTSP TCP connexion handle */
37
    /* XXX: currently we use unbuffered input */
38
    //    ByteIOContext rtsp_gb;
39
    int seq;        /* RTSP command sequence number */
40
    char session_id[512];
41
    enum RTSPProtocol protocol;
42
    char last_reply[2048]; /* XXX: allocate ? */
43
} RTSPState;
44

    
45
typedef struct RTSPStream {
46
    AVFormatContext *ic;
47
    int interleaved_min, interleaved_max;  /* interleave ids, if TCP transport */
48
    char control_url[1024]; /* url for this stream (from SDP) */
49

    
50
    int sdp_port; /* port (from SDP content - not used in RTSP) */
51
    struct in_addr sdp_ip; /* IP address  (from SDP content - not used in RTSP) */
52
    int sdp_ttl;  /* IP TTL (from SDP content - not used in RTSP) */
53
    int sdp_payload_type; /* payload type - only used in SDP */
54
} RTSPStream;
55

    
56
/* XXX: currently, the only way to change the protocols consists in
57
   changing this variable */
58
#if 1
59
int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP) | (1 << RTSP_PROTOCOL_RTP_UDP) | (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST);
60
#else
61
/* try it if a proxy is used */
62
int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP);
63
#endif
64

    
65
/* if non zero, then set a range for RTP ports */
66
int rtsp_rtp_port_min = 0;
67
int rtsp_rtp_port_max = 0;
68

    
69
FFRTSPCallback *ff_rtsp_callback = NULL;
70

    
71
static int rtsp_probe(AVProbeData *p)
72
{
73
    if (strstart(p->filename, "rtsp:", NULL))
74
        return AVPROBE_SCORE_MAX;
75
    return 0;
76
}
77

    
78
static int redir_isspace(int c)
79
{
80
    return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
81
}
82

    
83
static void skip_spaces(const char **pp)
84
{
85
    const char *p;
86
    p = *pp;
87
    while (redir_isspace(*p))
88
        p++;
89
    *pp = p;
90
}
91

    
92
static void get_word_sep(char *buf, int buf_size, const char *sep, 
93
                         const char **pp)
94
{
95
    const char *p;
96
    char *q;
97

    
98
    p = *pp;
99
    skip_spaces(&p);
100
    q = buf;
101
    while (!strchr(sep, *p) && *p != '\0') {
102
        if ((q - buf) < buf_size - 1)
103
            *q++ = *p;
104
        p++;
105
    }
106
    if (buf_size > 0)
107
        *q = '\0';
108
    *pp = p;
109
}
110

    
111
static void get_word(char *buf, int buf_size, const char **pp)
112
{
113
    const char *p;
114
    char *q;
115

    
116
    p = *pp;
117
    skip_spaces(&p);
118
    q = buf;
119
    while (!redir_isspace(*p) && *p != '\0') {
120
        if ((q - buf) < buf_size - 1)
121
            *q++ = *p;
122
        p++;
123
    }
124
    if (buf_size > 0)
125
        *q = '\0';
126
    *pp = p;
127
}
128

    
129
/* parse the rtpmap description: <codec_name>/<clock_rate>[/<other
130
   params>] */
131
static int sdp_parse_rtpmap(AVCodecContext *codec, const char *p)
132
{
133
    char buf[256];
134

    
135
    /* codec name */
136
    get_word_sep(buf, sizeof(buf), "/", &p);
137
    if (!strcmp(buf, "MP4V-ES")) {
138
        codec->codec_id = CODEC_ID_MPEG4;
139
        return 0;
140
    } else {
141
        return -1;
142
    }
143
}
144

    
145
/* return the length and optionnaly the data */
146
static int hex_to_data(uint8_t *data, const char *p)
147
{
148
    int c, len, v;
149

    
150
    len = 0;
151
    v = 1;
152
    for(;;) {
153
        skip_spaces(&p);
154
        if (p == '\0')
155
            break;
156
        c = toupper((unsigned char)*p++);
157
        if (c >= '0' && c <= '9')
158
            c = c - '0';
159
        else if (c >= 'A' && c <= 'F')
160
            c = c - 'A' + 10;
161
        else
162
            break;
163
        v = (v << 4) | c;
164
        if (v & 0x100) {
165
            if (data)
166
                data[len] = v;
167
            len++;
168
            v = 1;
169
        }
170
    }
171
    return len;
172
}
173

    
174
static void sdp_parse_fmtp(AVCodecContext *codec, const char *p)
175
{
176
    char attr[256];
177
    char value[4096];
178
    int len;
179

    
180
    /* loop on each attribute */
181
    for(;;) {
182
        skip_spaces(&p);
183
        if (*p == '\0')
184
            break;
185
        get_word_sep(attr, sizeof(attr), "=", &p);
186
        if (*p == '=') 
187
            p++;
188
        get_word_sep(value, sizeof(value), ";", &p);
189
        if (*p == ';')
190
            p++;
191
        /* handle MPEG4 video */
192
        switch(codec->codec_id) {
193
        case CODEC_ID_MPEG4:
194
            if (!strcmp(attr, "config")) {
195
                /* decode the hexa encoded parameter */
196
                len = hex_to_data(NULL, value);
197
                codec->extradata = av_mallocz(len);
198
                if (!codec->extradata)
199
                    goto fail;
200
                codec->extradata_size = len;
201
                hex_to_data(codec->extradata, value);
202
            }
203
            break;
204
        default:
205
            /* ignore data for other codecs */
206
            break;
207
        }
208
    fail: ;
209
        //        printf("'%s' = '%s'\n", attr, value);
210
    }
211
}
212

    
213
typedef struct SDPParseState {
214
    /* SDP only */
215
    struct in_addr default_ip;
216
    int default_ttl;
217
} SDPParseState;
218

    
219
static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
220
                           int letter, const char *buf)
221
{
222
    char buf1[64], st_type[64];
223
    const char *p;
224
    int codec_type, payload_type, i;
225
    AVStream *st;
226
    RTSPStream *rtsp_st;
227
    struct in_addr sdp_ip;
228
    int ttl;
229

    
230
#ifdef DEBUG
231
    printf("sdp: %c='%s'\n", letter, buf);
232
#endif
233

    
234
    p = buf;
235
    switch(letter) {
236
    case 'c':
237
        get_word(buf1, sizeof(buf1), &p);
238
        if (strcmp(buf1, "IN") != 0)
239
            return;
240
        get_word(buf1, sizeof(buf1), &p);
241
        if (strcmp(buf1, "IP4") != 0)
242
            return;
243
        get_word_sep(buf1, sizeof(buf1), "/", &p);
244
        if (inet_aton(buf1, &sdp_ip) == 0)
245
            return;
246
        ttl = 16;
247
        if (*p == '/') {
248
            p++;
249
            get_word_sep(buf1, sizeof(buf1), "/", &p);
250
            ttl = atoi(buf1);
251
        }
252
        if (s->nb_streams == 0) {
253
            s1->default_ip = sdp_ip;
254
            s1->default_ttl = ttl;
255
        } else {
256
            st = s->streams[s->nb_streams - 1];
257
            rtsp_st = st->priv_data;
258
            rtsp_st->sdp_ip = sdp_ip;
259
            rtsp_st->sdp_ttl = ttl;
260
        }
261
        break;
262
    case 's':
263
        pstrcpy(s->title, sizeof(s->title), p);
264
        break;
265
    case 'i':
266
        if (s->nb_streams == 0) {
267
            pstrcpy(s->comment, sizeof(s->comment), p);
268
            break;
269
        }
270
        break;
271
    case 'm':
272
        /* new stream */
273
        get_word(st_type, sizeof(st_type), &p);
274
        if (!strcmp(st_type, "audio")) {
275
            codec_type = CODEC_TYPE_AUDIO;
276
        } else if (!strcmp(st_type, "video")) {
277
            codec_type = CODEC_TYPE_VIDEO;
278
        } else {
279
            return;
280
        }
281
        rtsp_st = av_mallocz(sizeof(RTSPStream));
282
        if (!rtsp_st)
283
            return;
284
        st = av_new_stream(s, s->nb_streams);
285
        if (!st) 
286
            return;
287
        st->priv_data = rtsp_st;
288

    
289
        rtsp_st->sdp_ip = s1->default_ip;
290
        rtsp_st->sdp_ttl = s1->default_ttl;
291

    
292
        st->codec.codec_type = codec_type;
293

    
294
        get_word(buf1, sizeof(buf1), &p); /* port */
295
        rtsp_st->sdp_port = atoi(buf1);
296

    
297
        get_word(buf1, sizeof(buf1), &p); /* protocol (ignored) */
298
        
299
        /* XXX: handle list of formats */
300
        get_word(buf1, sizeof(buf1), &p); /* format list */
301
        rtsp_st->sdp_payload_type = atoi(buf1);
302
        if (rtsp_st->sdp_payload_type < 96) {
303
            /* if standard payload type, we can find the codec right now */
304
            rtp_get_codec_info(&st->codec, rtsp_st->sdp_payload_type);
305
        }
306

    
307
        /* put a default control url */
308
        pstrcpy(rtsp_st->control_url, sizeof(rtsp_st->control_url), s->filename);
309
        break;
310
    case 'a':
311
        if (strstart(p, "control:", &p) && s->nb_streams > 0) {
312
            char proto[32];
313
            /* get the control url */
314
            st = s->streams[s->nb_streams - 1];
315
            rtsp_st = st->priv_data;
316
            
317
            /* XXX: may need to add full url resolution */
318
            url_split(proto, sizeof(proto), NULL, 0, NULL, NULL, 0, p);
319
            if (proto[0] == '\0') {
320
                /* relative control URL */
321
                pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), "/");
322
                pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), p);
323
            } else {
324
                pstrcpy(rtsp_st->control_url, sizeof(rtsp_st->control_url), p);
325
            }
326
        } else if (strstart(p, "rtpmap:", &p)) {
327
            /* NOTE: rtpmap is only supported AFTER the 'm=' tag */
328
            get_word(buf1, sizeof(buf1), &p); 
329
            payload_type = atoi(buf1);
330
            for(i = 0; i < s->nb_streams;i++) {
331
                st = s->streams[i];
332
                rtsp_st = st->priv_data;
333
                if (rtsp_st->sdp_payload_type == payload_type) {
334
                    sdp_parse_rtpmap(&st->codec, p);
335
                }
336
            }
337
        } else if (strstart(p, "fmtp:", &p)) {
338
            /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */
339
            get_word(buf1, sizeof(buf1), &p); 
340
            payload_type = atoi(buf1);
341
            for(i = 0; i < s->nb_streams;i++) {
342
                st = s->streams[i];
343
                rtsp_st = st->priv_data;
344
                if (rtsp_st->sdp_payload_type == payload_type) {
345
                    sdp_parse_fmtp(&st->codec, p);
346
                }
347
            }
348
        }
349
        break;
350
    }
351
}
352

    
353
static int sdp_parse(AVFormatContext *s, const char *content)
354
{
355
    const char *p;
356
    int letter;
357
    char buf[1024], *q;
358
    SDPParseState sdp_parse_state, *s1 = &sdp_parse_state;
359
    
360
    memset(s1, 0, sizeof(SDPParseState));
361
    p = content;
362
    for(;;) {
363
        skip_spaces(&p);
364
        letter = *p;
365
        if (letter == '\0')
366
            break;
367
        p++;
368
        if (*p != '=')
369
            goto next_line;
370
        p++;
371
        /* get the content */
372
        q = buf;
373
        while (*p != '\n' && *p != '\r' && *p != '\0') {
374
            if ((q - buf) < sizeof(buf) - 1)
375
                *q++ = *p;
376
            p++;
377
        }
378
        *q = '\0';
379
        sdp_parse_line(s, s1, letter, buf);
380
    next_line:
381
        while (*p != '\n' && *p != '\0')
382
            p++;
383
        if (*p == '\n')
384
            p++;
385
    }
386
    return 0;
387
}
388

    
389
static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp)
390
{
391
    const char *p;
392
    int v;
393

    
394
    p = *pp;
395
    skip_spaces(&p);
396
    v = strtol(p, (char **)&p, 10);
397
    if (*p == '-') {
398
        p++;
399
        *min_ptr = v;
400
        v = strtol(p, (char **)&p, 10);
401
        *max_ptr = v;
402
    } else {
403
        *min_ptr = v;
404
        *max_ptr = v;
405
    }
406
    *pp = p;
407
}
408

    
409
/* XXX: only one transport specification is parsed */
410
static void rtsp_parse_transport(RTSPHeader *reply, const char *p)
411
{
412
    char transport_protocol[16];
413
    char profile[16];
414
    char lower_transport[16];
415
    char parameter[16];
416
    RTSPTransportField *th;
417
    char buf[256];
418
    
419
    reply->nb_transports = 0;
420
    
421
    for(;;) {
422
        skip_spaces(&p);
423
        if (*p == '\0')
424
            break;
425

    
426
        th = &reply->transports[reply->nb_transports];
427

    
428
        get_word_sep(transport_protocol, sizeof(transport_protocol), 
429
                     "/", &p);
430
        if (*p == '/')
431
            p++;
432
        get_word_sep(profile, sizeof(profile), "/;,", &p);
433
        lower_transport[0] = '\0';
434
        if (*p == '/') {
435
            p++;
436
            get_word_sep(lower_transport, sizeof(lower_transport), 
437
                         ";,", &p);
438
        }
439
        if (!strcasecmp(lower_transport, "TCP"))
440
            th->protocol = RTSP_PROTOCOL_RTP_TCP;
441
        else
442
            th->protocol = RTSP_PROTOCOL_RTP_UDP;
443
        
444
        if (*p == ';')
445
            p++;
446
        /* get each parameter */
447
        while (*p != '\0' && *p != ',') {
448
            get_word_sep(parameter, sizeof(parameter), "=;,", &p);
449
            if (!strcmp(parameter, "port")) {
450
                if (*p == '=') {
451
                    p++;
452
                    rtsp_parse_range(&th->port_min, &th->port_max, &p);
453
                }
454
            } else if (!strcmp(parameter, "client_port")) {
455
                if (*p == '=') {
456
                    p++;
457
                    rtsp_parse_range(&th->client_port_min, 
458
                                     &th->client_port_max, &p);
459
                }
460
            } else if (!strcmp(parameter, "server_port")) {
461
                if (*p == '=') {
462
                    p++;
463
                    rtsp_parse_range(&th->server_port_min, 
464
                                     &th->server_port_max, &p);
465
                }
466
            } else if (!strcmp(parameter, "interleaved")) {
467
                if (*p == '=') {
468
                    p++;
469
                    rtsp_parse_range(&th->interleaved_min, 
470
                                     &th->interleaved_max, &p);
471
                }
472
            } else if (!strcmp(parameter, "multicast")) {
473
                if (th->protocol == RTSP_PROTOCOL_RTP_UDP)
474
                    th->protocol = RTSP_PROTOCOL_RTP_UDP_MULTICAST;
475
            } else if (!strcmp(parameter, "ttl")) {
476
                if (*p == '=') {
477
                    p++;
478
                    th->ttl = strtol(p, (char **)&p, 10);
479
                }
480
            } else if (!strcmp(parameter, "destination")) {
481
                struct in_addr ipaddr;
482

    
483
                if (*p == '=') {
484
                    p++;
485
                    get_word_sep(buf, sizeof(buf), ";,", &p);
486
                    if (inet_aton(buf, &ipaddr)) 
487
                        th->destination = ntohl(ipaddr.s_addr);
488
                }
489
            }
490
            while (*p != ';' && *p != '\0' && *p != ',')
491
                p++;
492
            if (*p == ';')
493
                p++;
494
        }
495
        if (*p == ',')
496
            p++;
497

    
498
        reply->nb_transports++;
499
    }
500
}
501

    
502
void rtsp_parse_line(RTSPHeader *reply, const char *buf)
503
{
504
    const char *p;
505

    
506
    /* NOTE: we do case independent match for broken servers */
507
    p = buf;
508
    if (stristart(p, "Session:", &p)) {
509
        get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p);
510
    } else if (stristart(p, "Content-Length:", &p)) {
511
        reply->content_length = strtol(p, NULL, 10);
512
    } else if (stristart(p, "Transport:", &p)) {
513
        rtsp_parse_transport(reply, p);
514
    } else if (stristart(p, "CSeq:", &p)) {
515
        reply->seq = strtol(p, NULL, 10);
516
    }
517
}
518

    
519
/* skip a RTP/TCP interleaved packet */
520
static void rtsp_skip_packet(AVFormatContext *s)
521
{
522
    RTSPState *rt = s->priv_data;
523
    int ret, len, len1;
524
    uint8_t buf[1024];
525

    
526
    ret = url_read(rt->rtsp_hd, buf, 3);
527
    if (ret != 3)
528
        return;
529
    len = (buf[1] << 8) | buf[2];
530
#ifdef DEBUG
531
    printf("skipping RTP packet len=%d\n", len);
532
#endif
533
    /* skip payload */
534
    while (len > 0) {
535
        len1 = len;
536
        if (len1 > sizeof(buf))
537
            len1 = sizeof(buf);
538
        ret = url_read(rt->rtsp_hd, buf, len1);
539
        if (ret != len1)
540
            return;
541
        len -= len1;
542
    }
543
}
544

    
545
static void rtsp_send_cmd(AVFormatContext *s, 
546
                          const char *cmd, RTSPHeader *reply, 
547
                          unsigned char **content_ptr)
548
{
549
    RTSPState *rt = s->priv_data;
550
    char buf[4096], buf1[1024], *q;
551
    unsigned char ch;
552
    const char *p;
553
    int content_length, line_count;
554
    unsigned char *content = NULL;
555

    
556
    memset(reply, 0, sizeof(RTSPHeader));
557

    
558
    rt->seq++;
559
    pstrcpy(buf, sizeof(buf), cmd);
560
    snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq);
561
    pstrcat(buf, sizeof(buf), buf1);
562
    if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) {
563
        snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id);
564
        pstrcat(buf, sizeof(buf), buf1);
565
    }
566
    pstrcat(buf, sizeof(buf), "\r\n");
567
#ifdef DEBUG
568
    printf("Sending:\n%s--\n", buf);
569
#endif
570
    url_write(rt->rtsp_hd, buf, strlen(buf));
571

    
572
    /* parse reply (XXX: use buffers) */
573
    line_count = 0;
574
    rt->last_reply[0] = '\0';
575
    for(;;) {
576
        q = buf;
577
        for(;;) {
578
            if (url_read(rt->rtsp_hd, &ch, 1) != 1)
579
                break;
580
            if (ch == '\n')
581
                break;
582
            if (ch == '$') {
583
                /* XXX: only parse it if first char on line ? */
584
                rtsp_skip_packet(s);
585
            } else if (ch != '\r') {
586
                if ((q - buf) < sizeof(buf) - 1)
587
                    *q++ = ch;
588
            }
589
        }
590
        *q = '\0';
591
#ifdef DEBUG
592
        printf("line='%s'\n", buf);
593
#endif
594
        /* test if last line */
595
        if (buf[0] == '\0')
596
            break;
597
        p = buf;
598
        if (line_count == 0) {
599
            /* get reply code */
600
            get_word(buf1, sizeof(buf1), &p);
601
            get_word(buf1, sizeof(buf1), &p);
602
            reply->status_code = atoi(buf1);
603
        } else {
604
            rtsp_parse_line(reply, p);
605
            pstrcat(rt->last_reply, sizeof(rt->last_reply), p);
606
            pstrcat(rt->last_reply, sizeof(rt->last_reply), "\n");
607
        }
608
        line_count++;
609
    }
610
    
611
    if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0')
612
        pstrcpy(rt->session_id, sizeof(rt->session_id), reply->session_id);
613
    
614
    content_length = reply->content_length;
615
    if (content_length > 0) {
616
        /* leave some room for a trailing '\0' (useful for simple parsing) */
617
        content = av_malloc(content_length + 1);
618
        url_read(rt->rtsp_hd, content, content_length);
619
        content[content_length] = '\0';
620
    }
621
    if (content_ptr)
622
        *content_ptr = content;
623
}
624

    
625
/* useful for modules: set RTSP callback function */
626

    
627
void rtsp_set_callback(FFRTSPCallback *rtsp_cb)
628
{
629
    ff_rtsp_callback = rtsp_cb;
630
}
631

    
632

    
633
static int rtsp_read_header(AVFormatContext *s,
634
                            AVFormatParameters *ap)
635
{
636
    RTSPState *rt = s->priv_data;
637
    char host[1024], path[1024], tcpname[1024], cmd[2048];
638
    URLContext *rtsp_hd;
639
    int port, i, ret, err;
640
    RTSPHeader reply1, *reply = &reply1;
641
    unsigned char *content = NULL;
642
    AVStream *st;
643
    RTSPStream *rtsp_st;
644
    int protocol_mask;
645

    
646
    /* extract hostname and port */
647
    url_split(NULL, 0,
648
              host, sizeof(host), &port, path, sizeof(path), s->filename);
649
    if (port < 0)
650
        port = RTSP_DEFAULT_PORT;
651

    
652
    /* open the tcp connexion */
653
    snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port);
654
    if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0)
655
        return AVERROR_IO;
656
    rt->rtsp_hd = rtsp_hd;
657
    rt->seq = 0;
658
    
659
    /* describe the stream */
660
    snprintf(cmd, sizeof(cmd), 
661
             "DESCRIBE %s RTSP/1.0\r\n"
662
             "Accept: application/sdp\r\n",
663
             s->filename);
664
    rtsp_send_cmd(s, cmd, reply, &content);
665
    if (!content) {
666
        err = AVERROR_INVALIDDATA;
667
        goto fail;
668
    }
669
    if (reply->status_code != RTSP_STATUS_OK) {
670
        err = AVERROR_INVALIDDATA;
671
        goto fail;
672
    }
673
        
674
    /* now we got the SDP description, we parse it */
675
    ret = sdp_parse(s, (const char *)content);
676
    av_freep(&content);
677
    if (ret < 0) {
678
        err = AVERROR_INVALIDDATA;
679
        goto fail;
680
    }
681
    
682
    protocol_mask = rtsp_default_protocols;
683

    
684
    /* for each stream, make the setup request */
685
    /* XXX: we assume the same server is used for the control of each
686
       RTSP stream */
687
    for(i=0;i<s->nb_streams;i++) {
688
        char transport[2048];
689
        AVInputFormat *fmt;
690

    
691
        st = s->streams[i];
692
        rtsp_st = st->priv_data;
693

    
694
        /* compute available transports */
695
        transport[0] = '\0';
696

    
697
        /* RTP/UDP */
698
        if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP)) {
699
            char buf[256];
700
            int j;
701

    
702
            /* first try in specified port range */
703
            if (rtsp_rtp_port_min != 0) {
704
                for(j=rtsp_rtp_port_min;j<=rtsp_rtp_port_max;j++) {
705
                    snprintf(buf, sizeof(buf), "rtp://?localport=%d", j);
706
                    if (!av_open_input_file(&rtsp_st->ic, buf, 
707
                                            &rtp_demux, 0, NULL))
708
                        goto rtp_opened;
709
                }
710
            }
711

    
712
            /* then try on any port */
713
            if (av_open_input_file(&rtsp_st->ic, "rtp://", 
714
                                       &rtp_demux, 0, NULL) < 0) {
715
                    err = AVERROR_INVALIDDATA;
716
                    goto fail;
717
            }
718

    
719
        rtp_opened:
720
            port = rtp_get_local_port(url_fileno(&rtsp_st->ic->pb));
721
            if (transport[0] != '\0')
722
                pstrcat(transport, sizeof(transport), ",");
723
            snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1,
724
                     "RTP/AVP/UDP;unicast;client_port=%d-%d",
725
                     port, port + 1);
726
        }
727

    
728
        /* RTP/TCP */
729
        if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_TCP)) {
730
            if (transport[0] != '\0')
731
                pstrcat(transport, sizeof(transport), ",");
732
            snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1,
733
                     "RTP/AVP/TCP");
734
        }
735

    
736
        if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST)) {
737
            if (transport[0] != '\0')
738
                pstrcat(transport, sizeof(transport), ",");
739
            snprintf(transport + strlen(transport), 
740
                     sizeof(transport) - strlen(transport) - 1,
741
                     "RTP/AVP/UDP;multicast");
742
        }
743
        snprintf(cmd, sizeof(cmd), 
744
                 "SETUP %s RTSP/1.0\r\n"
745
                 "Transport: %s\r\n",
746
                 rtsp_st->control_url, transport);
747
        rtsp_send_cmd(s, cmd, reply, NULL);
748
        if (reply->status_code != RTSP_STATUS_OK ||
749
            reply->nb_transports != 1) {
750
            err = AVERROR_INVALIDDATA;
751
            goto fail;
752
        }
753

    
754
        /* XXX: same protocol for all streams is required */
755
        if (i > 0) {
756
            if (reply->transports[0].protocol != rt->protocol) {
757
                err = AVERROR_INVALIDDATA;
758
                goto fail;
759
            }
760
        } else {
761
            rt->protocol = reply->transports[0].protocol;
762
        }
763

    
764
        /* close RTP connection if not choosen */
765
        if (reply->transports[0].protocol != RTSP_PROTOCOL_RTP_UDP &&
766
            (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP))) {
767
            av_close_input_file(rtsp_st->ic);
768
            rtsp_st->ic = NULL;
769
        }
770

    
771
        switch(reply->transports[0].protocol) {
772
        case RTSP_PROTOCOL_RTP_TCP:
773
            fmt = &rtp_demux;
774
            if (av_open_input_file(&rtsp_st->ic, "null", fmt, 0, NULL) < 0) {
775
                err = AVERROR_INVALIDDATA;
776
                goto fail;
777
            }
778
            rtsp_st->interleaved_min = reply->transports[0].interleaved_min;
779
            rtsp_st->interleaved_max = reply->transports[0].interleaved_max;
780
            break;
781
            
782
        case RTSP_PROTOCOL_RTP_UDP:
783
            {
784
                char url[1024];
785
                
786
                /* XXX: also use address if specified */
787
                snprintf(url, sizeof(url), "rtp://%s:%d", 
788
                         host, reply->transports[0].server_port_min);
789
                if (rtp_set_remote_url(url_fileno(&rtsp_st->ic->pb), url) < 0) {
790
                    err = AVERROR_INVALIDDATA;
791
                    goto fail;
792
                }
793
            }
794
            break;
795
        case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
796
            {
797
                char url[1024];
798
                int ttl;
799

    
800
                fmt = &rtp_demux;
801
                ttl = reply->transports[0].ttl;
802
                if (!ttl)
803
                    ttl = 16;
804
                snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d", 
805
                         host, 
806
                         reply->transports[0].server_port_min,
807
                         ttl);
808
                if (av_open_input_file(&rtsp_st->ic, url, fmt, 0, NULL) < 0) {
809
                    err = AVERROR_INVALIDDATA;
810
                    goto fail;
811
                }
812
            }
813
            break;
814
        }
815
    }
816

    
817
    /* use callback if available to extend setup */
818
    if (ff_rtsp_callback) {
819
        if (ff_rtsp_callback(RTSP_ACTION_CLIENT_SETUP, rt->session_id, 
820
                             NULL, 0, rt->last_reply) < 0) {
821
            err = AVERROR_INVALIDDATA;
822
            goto fail;
823
        }
824
    }
825
                         
826
    /* start playing */
827
    snprintf(cmd, sizeof(cmd), 
828
             "PLAY %s RTSP/1.0\r\n"
829
             "Range: npt=0-\r\n",
830
             s->filename);
831
    rtsp_send_cmd(s, cmd, reply, NULL);
832
    if (reply->status_code != RTSP_STATUS_OK) {
833
        err = AVERROR_INVALIDDATA;
834
        goto fail;
835
    }
836

    
837
#if 0
838
    /* open TCP with bufferized input */
839
    if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) {
840
        if (url_fdopen(&rt->rtsp_gb, rt->rtsp_hd) < 0) {
841
            err = AVERROR_NOMEM;
842
            goto fail;
843
        }
844
    }
845
#endif
846

    
847
    return 0;
848
 fail:
849
    for(i=0;i<s->nb_streams;i++) {
850
        st = s->streams[i];
851
        rtsp_st = st->priv_data;
852
        if (rtsp_st) {
853
            if (rtsp_st->ic)
854
                av_close_input_file(rtsp_st->ic);
855
        }
856
        av_free(rtsp_st);
857
    }
858
    av_freep(&content);
859
    url_close(rt->rtsp_hd);
860
    return err;
861
}
862

    
863
static int tcp_read_packet(AVFormatContext *s,
864
                           AVPacket *pkt)
865
{
866
    RTSPState *rt = s->priv_data;
867
    int id, len, i, ret;
868
    AVStream *st;
869
    RTSPStream *rtsp_st;
870
    uint8_t buf[RTP_MAX_PACKET_LENGTH];
871

    
872
#ifdef DEBUG_RTP_TCP
873
    printf("tcp_read_packet:\n");
874
#endif
875
 redo:
876
    for(;;) {
877
        ret = url_read(rt->rtsp_hd, buf, 1);
878
#ifdef DEBUG_RTP_TCP
879
        printf("ret=%d c=%02x [%c]\n", ret, buf[0], buf[0]);
880
#endif
881
        if (ret != 1)
882
            return AVERROR_IO;
883
        if (buf[0] == '$')
884
            break;
885
    }
886
    ret = url_read(rt->rtsp_hd, buf, 3);
887
    if (ret != 3)
888
        return AVERROR_IO;
889
    id = buf[0];
890
    len = (buf[1] << 8) | buf[2];
891
#ifdef DEBUG_RTP_TCP
892
    printf("id=%d len=%d\n", id, len);
893
#endif
894
    if (len > RTP_MAX_PACKET_LENGTH || len < 12)
895
        goto redo;
896
    /* get the data */
897
    ret = url_read(rt->rtsp_hd, buf, len);
898
    if (ret != len)
899
        return AVERROR_IO;
900
        
901
    /* find the matching stream */
902
    for(i = 0; i < s->nb_streams; i++) {
903
        st = s->streams[i];
904
        rtsp_st = st->priv_data;
905
        if (id >= rtsp_st->interleaved_min && 
906
            id <= rtsp_st->interleaved_max) 
907
            goto found;
908
    }
909
    goto redo;
910
 found:
911
    ret = rtp_parse_packet(rtsp_st->ic, pkt, buf, len);
912
    if (ret < 0)
913
        goto redo;
914
    pkt->stream_index = i;
915
    return ret;
916
}
917

    
918
/* NOTE: output one packet at a time. May need to add a small fifo */
919
static int udp_read_packet(AVFormatContext *s,
920
                           AVPacket *pkt)
921
{
922
    AVFormatContext *ic;
923
    AVStream *st;
924
    RTSPStream *rtsp_st;
925
    fd_set rfds;
926
    int fd1, fd2, fd_max, n, i, ret;
927
    char buf[RTP_MAX_PACKET_LENGTH];
928
    struct timeval tv;
929

    
930
    for(;;) {
931
        if (url_interrupt_cb())
932
            return -EIO;
933
        FD_ZERO(&rfds);
934
        fd_max = -1;
935
        for(i = 0; i < s->nb_streams; i++) {
936
            st = s->streams[i];
937
            rtsp_st = st->priv_data;
938
            ic = rtsp_st->ic;
939
            /* currently, we cannot probe RTCP handle because of blocking restrictions */
940
            rtp_get_file_handles(url_fileno(&ic->pb), &fd1, &fd2);
941
            if (fd1 > fd_max)
942
                fd_max = fd1;
943
            FD_SET(fd1, &rfds);
944
        }
945
        /* XXX: also add proper API to abort */
946
        tv.tv_sec = 0;
947
        tv.tv_usec = 100 * 1000;
948
        n = select(fd_max + 1, &rfds, NULL, NULL, &tv);
949
        if (n > 0) {
950
            for(i = 0; i < s->nb_streams; i++) {
951
                st = s->streams[i];
952
                rtsp_st = st->priv_data;
953
                ic = rtsp_st->ic;
954
                rtp_get_file_handles(url_fileno(&ic->pb), &fd1, &fd2);
955
                if (FD_ISSET(fd1, &rfds)) {
956
                    ret = url_read(url_fileno(&ic->pb), buf, sizeof(buf));
957
                    if (ret >= 0 && 
958
                        rtp_parse_packet(ic, pkt, buf, ret) == 0) {
959
                        pkt->stream_index = i;
960
                        return ret;
961
                    }
962
                }
963
            }
964
        }
965
    }
966
}
967

    
968
static int rtsp_read_packet(AVFormatContext *s,
969
                            AVPacket *pkt)
970
{
971
    RTSPState *rt = s->priv_data;
972
    int ret;
973

    
974
    switch(rt->protocol) {
975
    default:
976
    case RTSP_PROTOCOL_RTP_TCP:
977
        ret = tcp_read_packet(s, pkt);
978
        break;
979
    case RTSP_PROTOCOL_RTP_UDP:
980
        ret = udp_read_packet(s, pkt);
981
        break;
982
    }
983
    return ret;
984
}
985

    
986
/* pause the stream */
987
int rtsp_pause(AVFormatContext *s)
988
{
989
    RTSPState *rt;
990
    RTSPHeader reply1, *reply = &reply1;
991
    char cmd[1024];
992

    
993
    if (s->iformat != &rtsp_demux)
994
        return -1;
995
    
996
    rt = s->priv_data;
997
    
998
    snprintf(cmd, sizeof(cmd), 
999
             "PAUSE %s RTSP/1.0\r\n",
1000
             s->filename);
1001
    rtsp_send_cmd(s, cmd, reply, NULL);
1002
    if (reply->status_code != RTSP_STATUS_OK) {
1003
        return -1;
1004
    } else {
1005
        return 0;
1006
    }
1007
}
1008

    
1009
/* resume the stream */
1010
int rtsp_resume(AVFormatContext *s)
1011
{
1012
    RTSPState *rt;
1013
    RTSPHeader reply1, *reply = &reply1;
1014
    char cmd[1024];
1015

    
1016
    if (s->iformat != &rtsp_demux)
1017
        return -1;
1018
    
1019
    rt = s->priv_data;
1020
    
1021
    snprintf(cmd, sizeof(cmd), 
1022
             "PLAY %s RTSP/1.0\r\n",
1023
             s->filename);
1024
    rtsp_send_cmd(s, cmd, reply, NULL);
1025
    if (reply->status_code != RTSP_STATUS_OK) {
1026
        return -1;
1027
    } else {
1028
        return 0;
1029
    }
1030
}
1031

    
1032
static int rtsp_read_close(AVFormatContext *s)
1033
{
1034
    RTSPState *rt = s->priv_data;
1035
    AVStream *st;
1036
    RTSPStream *rtsp_st;
1037
    RTSPHeader reply1, *reply = &reply1;
1038
    int i;
1039
    char cmd[1024];
1040

    
1041
#if 0
1042
    /* NOTE: it is valid to flush the buffer here */
1043
    if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) {
1044
        url_fclose(&rt->rtsp_gb);
1045
    }
1046
#endif
1047
    snprintf(cmd, sizeof(cmd), 
1048
             "TEARDOWN %s RTSP/1.0\r\n",
1049
             s->filename);
1050
    rtsp_send_cmd(s, cmd, reply, NULL);
1051

    
1052
    if (ff_rtsp_callback) {
1053
        ff_rtsp_callback(RTSP_ACTION_CLIENT_TEARDOWN, rt->session_id, 
1054
                         NULL, 0, NULL);
1055
    }
1056

    
1057
    for(i=0;i<s->nb_streams;i++) {
1058
        st = s->streams[i];
1059
        rtsp_st = st->priv_data;
1060
        if (rtsp_st) {
1061
            if (rtsp_st->ic)
1062
                av_close_input_file(rtsp_st->ic);
1063
        }
1064
        av_free(rtsp_st);
1065
    }
1066
    url_close(rt->rtsp_hd);
1067
    return 0;
1068
}
1069

    
1070
AVInputFormat rtsp_demux = {
1071
    "rtsp",
1072
    "RTSP input format",
1073
    sizeof(RTSPState),
1074
    rtsp_probe,
1075
    rtsp_read_header,
1076
    rtsp_read_packet,
1077
    rtsp_read_close,
1078
    .flags = AVFMT_NOFILE,
1079
};
1080

    
1081
static int sdp_probe(AVProbeData *p1)
1082
{
1083
    const char *p;
1084

    
1085
    /* we look for a line beginning "c=IN IP4" */
1086
    p = p1->buf;
1087
    while (*p != '\0') {
1088
        if (strstart(p, "c=IN IP4", NULL))
1089
            return AVPROBE_SCORE_MAX / 2;
1090
        p = strchr(p, '\n');
1091
        if (!p)
1092
            break;
1093
        p++;
1094
        if (*p == '\r')
1095
            p++;
1096
    }
1097
    return 0;
1098
}
1099

    
1100
#define SDP_MAX_SIZE 8192
1101

    
1102
static int sdp_read_header(AVFormatContext *s,
1103
                           AVFormatParameters *ap)
1104
{
1105
    AVStream *st;
1106
    RTSPStream *rtsp_st;
1107
    int size, i, err;
1108
    char *content;
1109
    char url[1024];
1110

    
1111
    /* read the whole sdp file */
1112
    /* XXX: better loading */
1113
    content = av_malloc(SDP_MAX_SIZE);
1114
    size = get_buffer(&s->pb, content, SDP_MAX_SIZE - 1);
1115
    if (size <= 0) {
1116
        av_free(content);
1117
        return AVERROR_INVALIDDATA;
1118
    }
1119
    content[size] ='\0';
1120

    
1121
    sdp_parse(s, content);
1122
    av_free(content);
1123

    
1124
    /* open each RTP stream */
1125
    for(i=0;i<s->nb_streams;i++) {
1126
        st = s->streams[i];
1127
        rtsp_st = st->priv_data;
1128
        
1129
        snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d", 
1130
                 inet_ntoa(rtsp_st->sdp_ip), 
1131
                 rtsp_st->sdp_port,
1132
                 rtsp_st->sdp_ttl);
1133
        if (av_open_input_file(&rtsp_st->ic, url, &rtp_demux, 0, NULL) < 0) {
1134
            err = AVERROR_INVALIDDATA;
1135
            goto fail;
1136
        }
1137
    }
1138
    return 0;
1139
 fail:
1140
    for(i=0;i<s->nb_streams;i++) {
1141
        st = s->streams[i];
1142
        rtsp_st = st->priv_data;
1143
        if (rtsp_st) {
1144
            if (rtsp_st->ic)
1145
                av_close_input_file(rtsp_st->ic);
1146
        }
1147
        av_free(rtsp_st);
1148
    }
1149
    return err;
1150
}
1151

    
1152
static int sdp_read_packet(AVFormatContext *s,
1153
                            AVPacket *pkt)
1154
{
1155
    return udp_read_packet(s, pkt);
1156
}
1157

    
1158
static int sdp_read_close(AVFormatContext *s)
1159
{
1160
    AVStream *st;
1161
    RTSPStream *rtsp_st;
1162
    int i;
1163

    
1164
    for(i=0;i<s->nb_streams;i++) {
1165
        st = s->streams[i];
1166
        rtsp_st = st->priv_data;
1167
        if (rtsp_st) {
1168
            if (rtsp_st->ic)
1169
                av_close_input_file(rtsp_st->ic);
1170
        }
1171
        av_free(rtsp_st);
1172
    }
1173
    return 0;
1174
}
1175

    
1176

    
1177
static AVInputFormat sdp_demux = {
1178
    "sdp",
1179
    "SDP",
1180
    sizeof(RTSPState),
1181
    sdp_probe,
1182
    sdp_read_header,
1183
    sdp_read_packet,
1184
    sdp_read_close,
1185
};
1186

    
1187

    
1188
/* dummy redirector format (used directly in av_open_input_file now) */
1189
static int redir_probe(AVProbeData *pd)
1190
{
1191
    const char *p;
1192
    p = pd->buf;
1193
    while (redir_isspace(*p))
1194
        p++;
1195
    if (strstart(p, "http://", NULL) ||
1196
        strstart(p, "rtsp://", NULL))
1197
        return AVPROBE_SCORE_MAX;
1198
    return 0;
1199
}
1200

    
1201
/* called from utils.c */
1202
int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f)
1203
{
1204
    char buf[4096], *q;
1205
    int c;
1206
    AVFormatContext *ic = NULL;
1207

    
1208
    /* parse each URL and try to open it */
1209
    c = url_fgetc(f);
1210
    while (c != URL_EOF) {
1211
        /* skip spaces */
1212
        for(;;) {
1213
            if (!redir_isspace(c))
1214
                break;
1215
            c = url_fgetc(f);
1216
        }
1217
        if (c == URL_EOF)
1218
            break;
1219
        /* record url */
1220
        q = buf;
1221
        for(;;) {
1222
            if (c == URL_EOF || redir_isspace(c))
1223
                break;
1224
            if ((q - buf) < sizeof(buf) - 1)
1225
                *q++ = c;
1226
            c = url_fgetc(f);
1227
        }
1228
        *q = '\0';
1229
        //printf("URL='%s'\n", buf);
1230
        /* try to open the media file */
1231
        if (av_open_input_file(&ic, buf, NULL, 0, NULL) == 0)
1232
            break;
1233
    }
1234
    *ic_ptr = ic;
1235
    if (!ic)
1236
        return AVERROR_IO;
1237
    else
1238
        return 0;
1239
}
1240

    
1241
AVInputFormat redir_demux = {
1242
    "redir",
1243
    "Redirector format",
1244
    0,
1245
    redir_probe,
1246
    NULL,
1247
    NULL,
1248
    NULL,
1249
};
1250

    
1251
int rtsp_init(void)
1252
{
1253
    av_register_input_format(&rtsp_demux);
1254
    av_register_input_format(&redir_demux);
1255
    av_register_input_format(&sdp_demux);
1256
    return 0;
1257
}