Statistics
| Branch: | Revision:

ffmpeg / libav / rtsp.c @ 9ddd71fc

History | View | Annotate | Download (25.2 KB)

1
/*
2
 * RTSP 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 <sys/time.h>
22
#include <netinet/in.h>
23
#include <sys/socket.h>
24
#ifndef __BEOS__
25
# include <arpa/inet.h>
26
#else
27
# include "barpainet.h"
28
#endif
29

    
30
//#define DEBUG
31

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

    
41
typedef struct RTSPStream {
42
    AVFormatContext *ic;
43
    int interleaved_min, interleaved_max;  /* interleave ids, if TCP transport */
44
    char control_url[1024]; /* url for this stream */
45
} RTSPStream;
46

    
47
/* suppress this hack */
48
int rtsp_abort_req = 0;
49

    
50
/* XXX: currently, the only way to change the protocols consists in
51
   changing this variable */
52
int rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP) | (1 << RTSP_PROTOCOL_RTP_UDP) | (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST);
53

    
54
/* if non zero, then set a range for RTP ports */
55
int rtsp_rtp_port_min = 0;
56
int rtsp_rtp_port_max = 0;
57

    
58
FFRTSPCallback *ff_rtsp_callback = NULL;
59

    
60
static int rtsp_probe(AVProbeData *p)
61
{
62
    if (strstart(p->filename, "rtsp:", NULL))
63
        return AVPROBE_SCORE_MAX;
64
    return 0;
65
}
66

    
67
static int redir_isspace(int c)
68
{
69
    return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
70
}
71

    
72
static void skip_spaces(const char **pp)
73
{
74
    const char *p;
75
    p = *pp;
76
    while (redir_isspace(*p))
77
        p++;
78
    *pp = p;
79
}
80

    
81
static void get_word_sep(char *buf, int buf_size, const char *sep, 
82
                         const char **pp)
83
{
84
    const char *p;
85
    char *q;
86

    
87
    p = *pp;
88
    skip_spaces(&p);
89
    q = buf;
90
    while (!strchr(sep, *p) && *p != '\0') {
91
        if ((q - buf) < buf_size - 1)
92
            *q++ = *p;
93
        p++;
94
    }
95
    if (buf_size > 0)
96
        *q = '\0';
97
    *pp = p;
98
}
99

    
100
static void get_word(char *buf, int buf_size, const char **pp)
101
{
102
    const char *p;
103
    char *q;
104

    
105
    p = *pp;
106
    skip_spaces(&p);
107
    q = buf;
108
    while (!redir_isspace(*p) && *p != '\0') {
109
        if ((q - buf) < buf_size - 1)
110
            *q++ = *p;
111
        p++;
112
    }
113
    if (buf_size > 0)
114
        *q = '\0';
115
    *pp = p;
116
}
117

    
118
static void sdp_parse_line(AVFormatContext *s, 
119
                           int letter, const char *buf)
120
{
121
    char buf1[64], st_type[64];
122
    const char *p;
123
    int codec_type, payload_type;
124
    AVStream *st;
125
    RTSPStream *rtsp_st;
126
    
127
#ifdef DEBUG
128
    printf("sdp: %c='%s'\n", letter, buf);
129
#endif
130

    
131
    p = buf;
132
    switch(letter) {
133
    case 's':
134
        pstrcpy(s->title, sizeof(s->title), p);
135
        break;
136
    case 'i':
137
        if (s->nb_streams == 0) {
138
            pstrcpy(s->comment, sizeof(s->comment), p);
139
            break;
140
        }
141
        break;
142
    case 'm':
143
        /* new stream */
144
        get_word(st_type, sizeof(st_type), &p);
145
        if (!strcmp(st_type, "audio")) {
146
            codec_type = CODEC_TYPE_AUDIO;
147
        } else if (!strcmp(st_type, "video")) {
148
            codec_type = CODEC_TYPE_VIDEO;
149
        } else {
150
            return;
151
        }
152
        get_word(buf1, sizeof(buf1), &p); /* port */
153
        get_word(buf1, sizeof(buf1), &p); /* protocol */
154
        /* XXX: handle list of formats */
155
        get_word(buf1, sizeof(buf1), &p); /* format list */
156
        payload_type = atoi(buf1);
157

    
158
        rtsp_st = av_mallocz(sizeof(RTSPStream));
159
        if (!rtsp_st)
160
            return;
161
        st = av_new_stream(s, s->nb_streams);
162
        if (!st) 
163
            return;
164
        st->priv_data = rtsp_st;
165
        /* put a default control url */
166
        pstrcpy(rtsp_st->control_url, sizeof(rtsp_st->control_url), s->filename);
167
        st->codec.codec_type = codec_type;
168
        rtp_get_codec_info(&st->codec, payload_type);
169
        break;
170
    case 'a':
171
        if (strstart(p, "control:", &p) && s->nb_streams > 0) {
172
            char proto[32];
173
            /* get the control url */
174
            st = s->streams[s->nb_streams - 1];
175
            rtsp_st = st->priv_data;
176
            
177
            /* XXX: may need to add full url resolution */
178
            url_split(proto, sizeof(proto), NULL, 0, NULL, NULL, 0, p);
179
            if (proto[0] == '\0') {
180
                /* relative control URL */
181
                pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), "/");
182
                pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), p);
183
            } else {
184
                pstrcpy(rtsp_st->control_url, sizeof(rtsp_st->control_url), p);
185
            }
186
        }
187
        break;
188
    }
189
}
190

    
191
int sdp_parse(AVFormatContext *s, const char *content)
192
{
193
    const char *p;
194
    int letter;
195
    char buf[1024], *q;
196

    
197
    p = content;
198
    for(;;) {
199
        skip_spaces(&p);
200
        letter = *p;
201
        if (letter == '\0')
202
            break;
203
        p++;
204
        if (*p != '=')
205
            goto next_line;
206
        p++;
207
        /* get the content */
208
        q = buf;
209
        while (*p != '\n' && *p != '\0') {
210
            if ((q - buf) < sizeof(buf) - 1)
211
                *q++ = *p;
212
            p++;
213
        }
214
        *q = '\0';
215
        sdp_parse_line(s, letter, buf);
216
    next_line:
217
        while (*p != '\n' && *p != '\0')
218
            p++;
219
        if (*p == '\n')
220
            p++;
221
    }
222
    return 0;
223
}
224

    
225
static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp)
226
{
227
    const char *p;
228
    int v;
229

    
230
    p = *pp;
231
    skip_spaces(&p);
232
    v = strtol(p, (char **)&p, 10);
233
    if (*p == '-') {
234
        p++;
235
        *min_ptr = v;
236
        v = strtol(p, (char **)&p, 10);
237
        *max_ptr = v;
238
    } else {
239
        *min_ptr = v;
240
        *max_ptr = v;
241
    }
242
    *pp = p;
243
}
244

    
245
/* XXX: only one transport specification is parsed */
246
static void rtsp_parse_transport(RTSPHeader *reply, const char *p)
247
{
248
    char transport_protocol[16];
249
    char profile[16];
250
    char lower_transport[16];
251
    char parameter[16];
252
    RTSPTransportField *th;
253
    char buf[256];
254
    
255
    reply->nb_transports = 0;
256
    
257
    for(;;) {
258
        skip_spaces(&p);
259
        if (*p == '\0')
260
            break;
261

    
262
        th = &reply->transports[reply->nb_transports];
263

    
264
        get_word_sep(transport_protocol, sizeof(transport_protocol), 
265
                     "/", &p);
266
        if (*p == '/')
267
            p++;
268
        get_word_sep(profile, sizeof(profile), "/;,", &p);
269
        lower_transport[0] = '\0';
270
        if (*p == '/') {
271
            get_word_sep(lower_transport, sizeof(lower_transport), 
272
                         ";,", &p);
273
        }
274
        if (!strcmp(lower_transport, "TCP"))
275
            th->protocol = RTSP_PROTOCOL_RTP_TCP;
276
        else
277
            th->protocol = RTSP_PROTOCOL_RTP_UDP;
278
        
279
        if (*p == ';')
280
            p++;
281
        /* get each parameter */
282
        while (*p != '\0' && *p != ',') {
283
            get_word_sep(parameter, sizeof(parameter), "=;,", &p);
284
            if (!strcmp(parameter, "port")) {
285
                if (*p == '=') {
286
                    p++;
287
                    rtsp_parse_range(&th->port_min, &th->port_max, &p);
288
                }
289
            } else if (!strcmp(parameter, "client_port")) {
290
                if (*p == '=') {
291
                    p++;
292
                    rtsp_parse_range(&th->client_port_min, 
293
                                     &th->client_port_max, &p);
294
                }
295
            } else if (!strcmp(parameter, "server_port")) {
296
                if (*p == '=') {
297
                    p++;
298
                    rtsp_parse_range(&th->server_port_min, 
299
                                     &th->server_port_max, &p);
300
                }
301
            } else if (!strcmp(parameter, "interleaved")) {
302
                if (*p == '=') {
303
                    p++;
304
                    rtsp_parse_range(&th->interleaved_min, 
305
                                     &th->interleaved_max, &p);
306
                }
307
            } else if (!strcmp(parameter, "multicast")) {
308
                if (th->protocol == RTSP_PROTOCOL_RTP_UDP)
309
                    th->protocol = RTSP_PROTOCOL_RTP_UDP_MULTICAST;
310
            } else if (!strcmp(parameter, "ttl")) {
311
                if (*p == '=') {
312
                    p++;
313
                    th->ttl = strtol(p, (char **)&p, 10);
314
                }
315
            } else if (!strcmp(parameter, "destination")) {
316
                struct in_addr ipaddr;
317

    
318
                if (*p == '=') {
319
                    p++;
320
                    get_word_sep(buf, sizeof(buf), ";,", &p);
321
                    if (inet_aton(buf, &ipaddr)) 
322
                        th->destination = ntohl(ipaddr.s_addr);
323
                }
324
            }
325
            while (*p != ';' && *p != '\0' && *p != ',')
326
                p++;
327
            if (*p == ';')
328
                p++;
329
        }
330
        if (*p == ',')
331
            p++;
332

    
333
        reply->nb_transports++;
334
    }
335
}
336

    
337
void rtsp_parse_line(RTSPHeader *reply, const char *buf)
338
{
339
    const char *p;
340

    
341
    /* NOTE: we do case independent match for broken servers */
342
    p = buf;
343
    if (stristart(p, "Session:", &p)) {
344
        get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p);
345
    } else if (stristart(p, "Content-Length:", &p)) {
346
        reply->content_length = strtol(p, NULL, 10);
347
    } else if (stristart(p, "Transport:", &p)) {
348
        rtsp_parse_transport(reply, p);
349
    } else if (stristart(p, "CSeq:", &p)) {
350
        reply->seq = strtol(p, NULL, 10);
351
    }
352
}
353

    
354

    
355
static void rtsp_send_cmd(AVFormatContext *s, 
356
                          const char *cmd, RTSPHeader *reply, 
357
                          unsigned char **content_ptr)
358
{
359
    RTSPState *rt = s->priv_data;
360
    char buf[4096], buf1[1024], *q;
361
    unsigned char ch;
362
    const char *p;
363
    int content_length, line_count;
364
    unsigned char *content = NULL;
365

    
366
    memset(reply, 0, sizeof(RTSPHeader));
367

    
368
    rt->seq++;
369
    pstrcpy(buf, sizeof(buf), cmd);
370
    snprintf(buf1, sizeof(buf1), "CSeq: %d\n", rt->seq);
371
    pstrcat(buf, sizeof(buf), buf1);
372
    if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) {
373
        snprintf(buf1, sizeof(buf1), "Session: %s\n", rt->session_id);
374
        pstrcat(buf, sizeof(buf), buf1);
375
    }
376
    pstrcat(buf, sizeof(buf), "\n");
377
#ifdef DEBUG
378
    printf("Sending:\n%s--\n", buf);
379
#endif
380
    url_write(rt->rtsp_hd, buf, strlen(buf));
381

    
382
    /* parse reply (XXX: use buffers) */
383
    line_count = 0;
384
    rt->last_reply[0] = '\0';
385
    for(;;) {
386
        q = buf;
387
        for(;;) {
388
            if (url_read(rt->rtsp_hd, &ch, 1) == 0)
389
                break;
390
            if (ch == '\n')
391
                break;
392
            if (ch != '\r') {
393
                if ((q - buf) < sizeof(buf) - 1)
394
                    *q++ = ch;
395
            }
396
        }
397
        *q = '\0';
398
#ifdef DEBUG
399
        printf("line='%s'\n", buf);
400
#endif
401
        /* test if last line */
402
        if (buf[0] == '\0')
403
            break;
404
        p = buf;
405
        if (line_count == 0) {
406
            /* get reply code */
407
            get_word(buf1, sizeof(buf1), &p);
408
            get_word(buf1, sizeof(buf1), &p);
409
            reply->status_code = atoi(buf1);
410
        } else {
411
            rtsp_parse_line(reply, p);
412
            pstrcat(rt->last_reply, sizeof(rt->last_reply), p);
413
            pstrcat(rt->last_reply, sizeof(rt->last_reply), "\n");
414
        }
415
        line_count++;
416
    }
417
    
418
    if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0')
419
        pstrcpy(rt->session_id, sizeof(rt->session_id), reply->session_id);
420
    
421
    content_length = reply->content_length;
422
    if (content_length > 0) {
423
        /* leave some room for a trailing '\0' (useful for simple parsing) */
424
        content = av_malloc(content_length + 1);
425
        url_read(rt->rtsp_hd, content, content_length);
426
        content[content_length] = '\0';
427
    }
428
    if (content_ptr)
429
        *content_ptr = content;
430
}
431

    
432
/* useful for modules: set RTSP callback function */
433

    
434
void rtsp_set_callback(FFRTSPCallback *rtsp_cb)
435
{
436
    ff_rtsp_callback = rtsp_cb;
437
}
438

    
439

    
440
static int rtsp_read_header(AVFormatContext *s,
441
                            AVFormatParameters *ap)
442
{
443
    RTSPState *rt = s->priv_data;
444
    char host[1024], path[1024], tcpname[1024], cmd[2048];
445
    URLContext *rtsp_hd;
446
    int port, i, ret, err;
447
    RTSPHeader reply1, *reply = &reply1;
448
    unsigned char *content = NULL;
449
    AVStream *st;
450
    RTSPStream *rtsp_st;
451
    int protocol_mask;
452

    
453
    rtsp_abort_req = 0;
454
    
455
    /* extract hostname and port */
456
    url_split(NULL, 0,
457
              host, sizeof(host), &port, path, sizeof(path), s->filename);
458
    if (port < 0)
459
        port = RTSP_DEFAULT_PORT;
460

    
461
    /* open the tcp connexion */
462
    snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port);
463
    if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0)
464
        return AVERROR_IO;
465
    rt->rtsp_hd = rtsp_hd;
466
    rt->seq = 0;
467
    
468
    /* describe the stream */
469
    snprintf(cmd, sizeof(cmd), 
470
             "DESCRIBE %s RTSP/1.0\n"
471
             "Accept: application/sdp\n",
472
             s->filename);
473
    rtsp_send_cmd(s, cmd, reply, &content);
474
    if (!content) {
475
        err = AVERROR_INVALIDDATA;
476
        goto fail;
477
    }
478
    if (reply->status_code != RTSP_STATUS_OK) {
479
        err = AVERROR_INVALIDDATA;
480
        goto fail;
481
    }
482
        
483
    /* now we got the SDP description, we parse it */
484
    ret = sdp_parse(s, (const char *)content);
485
    av_freep(&content);
486
    if (ret < 0) {
487
        err = AVERROR_INVALIDDATA;
488
        goto fail;
489
    }
490
    
491
    protocol_mask = rtsp_default_protocols;
492

    
493
    /* for each stream, make the setup request */
494
    /* XXX: we assume the same server is used for the control of each
495
       RTSP stream */
496
    for(i=0;i<s->nb_streams;i++) {
497
        char transport[2048];
498
        AVInputFormat *fmt;
499

    
500
        st = s->streams[i];
501
        rtsp_st = st->priv_data;
502

    
503
        /* compute available transports */
504
        transport[0] = '\0';
505

    
506
        /* RTP/UDP */
507
        if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP)) {
508
            char buf[256];
509
            int j;
510

    
511
            /* first try in specified port range */
512
            if (rtsp_rtp_port_min != 0) {
513
                for(j=rtsp_rtp_port_min;j<=rtsp_rtp_port_max;j++) {
514
                    snprintf(buf, sizeof(buf), "rtp://?localport=%d", j);
515
                    if (!av_open_input_file(&rtsp_st->ic, buf, 
516
                                            &rtp_demux, 0, NULL))
517
                        goto rtp_opened;
518
                }
519
            }
520

    
521
            /* then try on any port */
522
            if (av_open_input_file(&rtsp_st->ic, "rtp://", 
523
                                       &rtp_demux, 0, NULL) < 0) {
524
                    err = AVERROR_INVALIDDATA;
525
                    goto fail;
526
            }
527

    
528
        rtp_opened:
529
            port = rtp_get_local_port(url_fileno(&rtsp_st->ic->pb));
530
            if (transport[0] != '\0')
531
                pstrcat(transport, sizeof(transport), ",");
532
            snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1,
533
                     "RTP/AVP/UDP;unicast;client_port=%d-%d",
534
                     port, port + 1);
535
        }
536

    
537
        /* RTP/TCP */
538
        if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_TCP)) {
539
            if (transport[0] != '\0')
540
                pstrcat(transport, sizeof(transport), ",");
541
            snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1,
542
                     "RTP/AVP/TCP");
543
        }
544

    
545
        if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST)) {
546
            if (transport[0] != '\0')
547
                pstrcat(transport, sizeof(transport), ",");
548
            snprintf(transport + strlen(transport), 
549
                     sizeof(transport) - strlen(transport) - 1,
550
                     "RTP/AVP/UDP;multicast");
551
        }
552
        
553
        snprintf(cmd, sizeof(cmd), 
554
                 "SETUP %s RTSP/1.0\n"
555
                 "Transport: %s\n",
556
                 rtsp_st->control_url, transport);
557
        rtsp_send_cmd(s, cmd, reply, NULL);
558
        if (reply->status_code != RTSP_STATUS_OK ||
559
            reply->nb_transports != 1) {
560
            err = AVERROR_INVALIDDATA;
561
            goto fail;
562
        }
563

    
564
        /* XXX: same protocol for all streams is required */
565
        if (i > 0) {
566
            if (reply->transports[0].protocol != rt->protocol) {
567
                err = AVERROR_INVALIDDATA;
568
                goto fail;
569
            }
570
        } else {
571
            rt->protocol = reply->transports[0].protocol;
572
        }
573

    
574
        /* close RTP connection if not choosen */
575
        if (reply->transports[0].protocol != RTSP_PROTOCOL_RTP_UDP &&
576
            (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP))) {
577
            av_close_input_file(rtsp_st->ic);
578
            rtsp_st->ic = NULL;
579
        }
580

    
581
        switch(reply->transports[0].protocol) {
582
        case RTSP_PROTOCOL_RTP_TCP:
583
            fmt = &rtp_demux;
584
            if (av_open_input_file(&rtsp_st->ic, "null", fmt, 0, NULL) < 0) {
585
                err = AVERROR_INVALIDDATA;
586
                goto fail;
587
            }
588
            rtsp_st->interleaved_min = reply->transports[0].interleaved_min;
589
            rtsp_st->interleaved_max = reply->transports[0].interleaved_max;
590
            break;
591
            
592
        case RTSP_PROTOCOL_RTP_UDP:
593
            {
594
                char url[1024];
595
                
596
                /* XXX: also use address if specified */
597
                snprintf(url, sizeof(url), "rtp://%s:%d", 
598
                         host, reply->transports[0].server_port_min);
599
                if (rtp_set_remote_url(url_fileno(&rtsp_st->ic->pb), url) < 0) {
600
                    err = AVERROR_INVALIDDATA;
601
                    goto fail;
602
                }
603
            }
604
            break;
605
        case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
606
            {
607
                char url[1024];
608
                int ttl;
609

    
610
                fmt = &rtp_demux;
611
                ttl = reply->transports[0].ttl;
612
                if (!ttl)
613
                    ttl = 16;
614
                snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d", 
615
                         host, 
616
                         reply->transports[0].server_port_min,
617
                         ttl);
618
                if (av_open_input_file(&rtsp_st->ic, url, fmt, 0, NULL) < 0) {
619
                    err = AVERROR_INVALIDDATA;
620
                    goto fail;
621
                }
622
            }
623
            break;
624
        }
625
    }
626

    
627
    /* use callback if available to extend setup */
628
    if (ff_rtsp_callback) {
629
        if (ff_rtsp_callback(RTSP_ACTION_CLIENT_SETUP, rt->session_id, 
630
                             NULL, 0, rt->last_reply) < 0) {
631
            err = AVERROR_INVALIDDATA;
632
            goto fail;
633
        }
634
    }
635
                         
636
    /* start playing */
637
    snprintf(cmd, sizeof(cmd), 
638
             "PLAY %s RTSP/1.0\n",
639
             s->filename);
640
    rtsp_send_cmd(s, cmd, reply, NULL);
641
    if (reply->status_code != RTSP_STATUS_OK) {
642
        err = AVERROR_INVALIDDATA;
643
        goto fail;
644
    }
645

    
646
    /* open TCP with bufferized input */
647
    if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) {
648
        if (url_fdopen(&rt->rtsp_gb, rt->rtsp_hd) < 0) {
649
            err = AVERROR_NOMEM;
650
            goto fail;
651
        }
652
    }
653

    
654
    return 0;
655
 fail:
656
    for(i=0;i<s->nb_streams;i++) {
657
        st = s->streams[i];
658
        rtsp_st = st->priv_data;
659
        if (rtsp_st) {
660
            if (rtsp_st->ic)
661
                av_close_input_file(rtsp_st->ic);
662
        }
663
        av_free(rtsp_st);
664
    }
665
    av_freep(&content);
666
    url_close(rt->rtsp_hd);
667
    return err;
668
}
669

    
670
static int tcp_read_packet(AVFormatContext *s,
671
                           AVPacket *pkt)
672
{
673
    RTSPState *rt = s->priv_data;
674
    ByteIOContext *rtsp_gb = &rt->rtsp_gb;
675
    int c, id, len, i, ret;
676
    AVStream *st;
677
    RTSPStream *rtsp_st;
678
    char buf[RTP_MAX_PACKET_LENGTH];
679

    
680
 redo:
681
    for(;;) {
682
        c = url_fgetc(rtsp_gb);
683
        if (c == URL_EOF)
684
            return AVERROR_IO;
685
        if (c == '$')
686
            break;
687
    }
688
    id = get_byte(rtsp_gb);
689
    len = get_be16(rtsp_gb);
690
    if (len > RTP_MAX_PACKET_LENGTH || len < 12)
691
        goto redo;
692
    /* get the data */
693
    get_buffer(rtsp_gb, buf, len);
694
    
695
    /* find the matching stream */
696
    for(i = 0; i < s->nb_streams; i++) {
697
        st = s->streams[i];
698
        rtsp_st = st->priv_data;
699
        if (i >= rtsp_st->interleaved_min && 
700
            i <= rtsp_st->interleaved_max) 
701
            goto found;
702
    }
703
    goto redo;
704
 found:
705
    ret = rtp_parse_packet(rtsp_st->ic, pkt, buf, len);
706
    if (ret < 0)
707
        goto redo;
708
    pkt->stream_index = i;
709
    return ret;
710
}
711

    
712
/* NOTE: output one packet at a time. May need to add a small fifo */
713
static int udp_read_packet(AVFormatContext *s,
714
                           AVPacket *pkt)
715
{
716
    AVFormatContext *ic;
717
    AVStream *st;
718
    RTSPStream *rtsp_st;
719
    fd_set rfds;
720
    int fd1, fd2, fd_max, n, i, ret;
721
    char buf[RTP_MAX_PACKET_LENGTH];
722
    struct timeval tv;
723

    
724
    for(;;) {
725
        if (rtsp_abort_req)
726
            return -EIO;
727
        FD_ZERO(&rfds);
728
        fd_max = -1;
729
        for(i = 0; i < s->nb_streams; i++) {
730
            st = s->streams[i];
731
            rtsp_st = st->priv_data;
732
            ic = rtsp_st->ic;
733
            /* currently, we cannot probe RTCP handle because of blocking restrictions */
734
            rtp_get_file_handles(url_fileno(&ic->pb), &fd1, &fd2);
735
            if (fd1 > fd_max)
736
                fd_max = fd1;
737
            FD_SET(fd1, &rfds);
738
        }
739
        /* XXX: also add proper API to abort */
740
        tv.tv_sec = 0;
741
        tv.tv_usec = 500000;
742
        n = select(fd_max + 1, &rfds, NULL, NULL, &tv);
743
        if (n > 0) {
744
            for(i = 0; i < s->nb_streams; i++) {
745
                st = s->streams[i];
746
                rtsp_st = st->priv_data;
747
                ic = rtsp_st->ic;
748
                rtp_get_file_handles(url_fileno(&ic->pb), &fd1, &fd2);
749
                if (FD_ISSET(fd1, &rfds)) {
750
                    ret = url_read(url_fileno(&ic->pb), buf, sizeof(buf));
751
                    if (ret >= 0 && 
752
                        rtp_parse_packet(ic, pkt, buf, ret) == 0) {
753
                        pkt->stream_index = i;
754
                        return ret;
755
                    }
756
                }
757
            }
758
        }
759
    }
760
}
761

    
762
static int rtsp_read_packet(AVFormatContext *s,
763
                            AVPacket *pkt)
764
{
765
    RTSPState *rt = s->priv_data;
766
    int ret;
767

    
768
    switch(rt->protocol) {
769
    default:
770
    case RTSP_PROTOCOL_RTP_TCP:
771
        ret = tcp_read_packet(s, pkt);
772
        break;
773
    case RTSP_PROTOCOL_RTP_UDP:
774
        ret = udp_read_packet(s, pkt);
775
        break;
776
    }
777
    return ret;
778
}
779

    
780
static int rtsp_read_close(AVFormatContext *s)
781
{
782
    RTSPState *rt = s->priv_data;
783
    AVStream *st;
784
    RTSPStream *rtsp_st;
785
    RTSPHeader reply1, *reply = &reply1;
786
    int i;
787
    char cmd[1024];
788

    
789
    /* NOTE: it is valid to flush the buffer here */
790
    if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) {
791
        url_fclose(&rt->rtsp_gb);
792
    }
793

    
794
    snprintf(cmd, sizeof(cmd), 
795
             "TEARDOWN %s RTSP/1.0\n",
796
             s->filename);
797
    rtsp_send_cmd(s, cmd, reply, NULL);
798

    
799
    if (ff_rtsp_callback) {
800
        ff_rtsp_callback(RTSP_ACTION_CLIENT_TEARDOWN, rt->session_id, 
801
                         NULL, 0, NULL);
802
    }
803

    
804
    for(i=0;i<s->nb_streams;i++) {
805
        st = s->streams[i];
806
        rtsp_st = st->priv_data;
807
        if (rtsp_st) {
808
            if (rtsp_st->ic)
809
                av_close_input_file(rtsp_st->ic);
810
        }
811
        av_free(rtsp_st);
812
    }
813
    url_close(rt->rtsp_hd);
814
    return 0;
815
}
816

    
817
static AVInputFormat rtsp_demux = {
818
    "rtsp",
819
    "RTSP input format",
820
    sizeof(RTSPState),
821
    rtsp_probe,
822
    rtsp_read_header,
823
    rtsp_read_packet,
824
    rtsp_read_close,
825
    .flags = AVFMT_NOFILE,
826
};
827

    
828
/* dummy redirector format (used directly in av_open_input_file now) */
829
static int redir_probe(AVProbeData *pd)
830
{
831
    const char *p;
832
    p = pd->buf;
833
    while (redir_isspace(*p))
834
        p++;
835
    if (strstart(p, "http://", NULL) ||
836
        strstart(p, "rtsp://", NULL))
837
        return AVPROBE_SCORE_MAX;
838
    return 0;
839
}
840

    
841
/* called from utils.c */
842
int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f)
843
{
844
    char buf[4096], *q;
845
    int c;
846
    AVFormatContext *ic = NULL;
847

    
848
    /* parse each URL and try to open it */
849
    c = url_fgetc(f);
850
    while (c != URL_EOF) {
851
        /* skip spaces */
852
        for(;;) {
853
            if (!redir_isspace(c))
854
                break;
855
            c = url_fgetc(f);
856
        }
857
        if (c == URL_EOF)
858
            break;
859
        /* record url */
860
        q = buf;
861
        for(;;) {
862
            if (c == URL_EOF || redir_isspace(c))
863
                break;
864
            if ((q - buf) < sizeof(buf) - 1)
865
                *q++ = c;
866
            c = url_fgetc(f);
867
        }
868
        *q = '\0';
869
        //printf("URL='%s'\n", buf);
870
        /* try to open the media file */
871
        if (av_open_input_file(&ic, buf, NULL, 0, NULL) == 0)
872
            break;
873
    }
874
    *ic_ptr = ic;
875
    if (!ic)
876
        return AVERROR_IO;
877
    else
878
        return 0;
879
}
880

    
881
AVInputFormat redir_demux = {
882
    "redir",
883
    "Redirector format",
884
    0,
885
    redir_probe,
886
    NULL,
887
    NULL,
888
    NULL,
889
};
890

    
891
int rtsp_init(void)
892
{
893
    av_register_input_format(&rtsp_demux);
894
    av_register_input_format(&redir_demux);
895
    return 0;
896
}