Statistics
| Branch: | Revision:

ffmpeg / libavformat / rtsp.c @ 5aa0a644

History | View | Annotate | Download (34.3 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
#ifndef __BEOS__
26
# include <arpa/inet.h>
27
#else
28
# include "barpainet.h"
29
#endif
30

    
31
//#define DEBUG
32
//#define DEBUG_RTP_TCP
33

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

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

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

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

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

    
68
FFRTSPCallback *ff_rtsp_callback = NULL;
69

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
291
        st->codec.codec_type = codec_type;
292

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
631

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1099
#define SDP_MAX_SIZE 8192
1100

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

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

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

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

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

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

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

    
1175

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

    
1186

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

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

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

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

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