3 * Copyright (c) 2002 Fabrice Bellard.
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.
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.
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
22 #include <netinet/in.h>
23 #include <sys/socket.h>
26 # include <arpa/inet.h>
28 # include "barpainet.h"
33 typedef struct RTSPState
{
34 URLContext
*rtsp_hd
; /* RTSP TCP connexion handle */
35 ByteIOContext rtsp_gb
;
36 int seq
; /* RTSP command sequence number */
38 enum RTSPProtocol protocol
;
39 char last_reply
[2048]; /* XXX: allocate ? */
42 typedef struct RTSPStream
{
44 int interleaved_min
, interleaved_max
; /* interleave ids, if TCP transport */
45 char control_url
[1024]; /* url for this stream (from SDP) */
47 int sdp_port
; /* port (from SDP content - not used in RTSP) */
48 struct in_addr sdp_ip
; /* IP address (from SDP content - not used in RTSP) */
49 int sdp_ttl
; /* IP TTL (from SDP content - not used in RTSP) */
50 int sdp_payload_type
; /* payload type - only used in SDP */
53 /* suppress this hack */
54 int rtsp_abort_req
= 0;
56 /* XXX: currently, the only way to change the protocols consists in
57 changing this variable */
58 int rtsp_default_protocols
= (1 << RTSP_PROTOCOL_RTP_TCP
) | (1 << RTSP_PROTOCOL_RTP_UDP
) | (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST
);
60 /* if non zero, then set a range for RTP ports */
61 int rtsp_rtp_port_min
= 0;
62 int rtsp_rtp_port_max
= 0;
64 FFRTSPCallback
*ff_rtsp_callback
= NULL
;
66 static int rtsp_probe(AVProbeData
*p
)
68 if (strstart(p
->filename
, "rtsp:", NULL
))
69 return AVPROBE_SCORE_MAX
;
73 static int redir_isspace(int c
)
75 return (c
== ' ' || c
== '\t' || c
== '\n' || c
== '\r');
78 static void skip_spaces(const char **pp
)
82 while (redir_isspace(*p
))
87 static void get_word_sep(char *buf
, int buf_size
, const char *sep
,
96 while (!strchr(sep
, *p
) && *p
!= '\0') {
97 if ((q
- buf
) < buf_size
- 1)
106 static void get_word(char *buf
, int buf_size
, const char **pp
)
114 while (!redir_isspace(*p
) && *p
!= '\0') {
115 if ((q
- buf
) < buf_size
- 1)
124 /* parse the rtpmap description: <codec_name>/<clock_rate>[/<other
126 static int sdp_parse_rtpmap(AVCodecContext
*codec
, const char *p
)
131 get_word_sep(buf
, sizeof(buf
), "/", &p
);
132 if (!strcmp(buf
, "MP4V-ES")) {
133 codec
->codec_id
= CODEC_ID_MPEG4
;
140 /* return the length and optionnaly the data */
141 static int hex_to_data(uint8_t *data
, const char *p
)
151 c
= toupper((unsigned char)*p
++);
152 if (c
>= '0' && c
<= '9')
154 else if (c
>= 'A' && c
<= 'F')
169 static void sdp_parse_fmtp(AVCodecContext
*codec
, const char *p
)
175 /* loop on each attribute */
180 get_word_sep(attr
, sizeof(attr
), "=", &p
);
183 get_word_sep(value
, sizeof(value
), ";", &p
);
186 /* handle MPEG4 video */
187 switch(codec
->codec_id
) {
189 if (!strcmp(attr
, "config")) {
190 /* decode the hexa encoded parameter */
191 len
= hex_to_data(NULL
, value
);
192 codec
->extradata
= av_mallocz(len
);
193 if (!codec
->extradata
)
195 codec
->extradata_size
= len
;
196 hex_to_data(codec
->extradata
, value
);
200 /* ignore data for other codecs */
204 // printf("'%s' = '%s'\n", attr, value);
208 typedef struct SDPParseState
{
210 struct in_addr default_ip
;
214 static void sdp_parse_line(AVFormatContext
*s
, SDPParseState
*s1
,
215 int letter
, const char *buf
)
217 char buf1
[64], st_type
[64];
219 int codec_type
, payload_type
, i
;
222 struct in_addr sdp_ip
;
226 printf("sdp: %c='%s'\n", letter
, buf
);
232 get_word(buf1
, sizeof(buf1
), &p
);
233 if (strcmp(buf1
, "IN") != 0)
235 get_word(buf1
, sizeof(buf1
), &p
);
236 if (strcmp(buf1
, "IP4") != 0)
238 get_word_sep(buf1
, sizeof(buf1
), "/", &p
);
239 if (inet_aton(buf1
, &sdp_ip
) == 0)
244 get_word_sep(buf1
, sizeof(buf1
), "/", &p
);
247 if (s
->nb_streams
== 0) {
248 s1
->default_ip
= sdp_ip
;
249 s1
->default_ttl
= ttl
;
251 st
= s
->streams
[s
->nb_streams
- 1];
252 rtsp_st
= st
->priv_data
;
253 rtsp_st
->sdp_ip
= sdp_ip
;
254 rtsp_st
->sdp_ttl
= ttl
;
258 pstrcpy(s
->title
, sizeof(s
->title
), p
);
261 if (s
->nb_streams
== 0) {
262 pstrcpy(s
->comment
, sizeof(s
->comment
), p
);
268 get_word(st_type
, sizeof(st_type
), &p
);
269 if (!strcmp(st_type
, "audio")) {
270 codec_type
= CODEC_TYPE_AUDIO
;
271 } else if (!strcmp(st_type
, "video")) {
272 codec_type
= CODEC_TYPE_VIDEO
;
276 rtsp_st
= av_mallocz(sizeof(RTSPStream
));
279 st
= av_new_stream(s
, s
->nb_streams
);
282 st
->priv_data
= rtsp_st
;
284 rtsp_st
->sdp_ip
= s1
->default_ip
;
285 rtsp_st
->sdp_ttl
= s1
->default_ttl
;
287 st
->codec
.codec_type
= codec_type
;
289 get_word(buf1
, sizeof(buf1
), &p
); /* port */
290 rtsp_st
->sdp_port
= atoi(buf1
);
292 get_word(buf1
, sizeof(buf1
), &p
); /* protocol (ignored) */
294 /* XXX: handle list of formats */
295 get_word(buf1
, sizeof(buf1
), &p
); /* format list */
296 rtsp_st
->sdp_payload_type
= atoi(buf1
);
297 if (rtsp_st
->sdp_payload_type
< 96) {
298 /* if standard payload type, we can find the codec right now */
299 rtp_get_codec_info(&st
->codec
, rtsp_st
->sdp_payload_type
);
302 /* put a default control url */
303 pstrcpy(rtsp_st
->control_url
, sizeof(rtsp_st
->control_url
), s
->filename
);
306 if (strstart(p
, "control:", &p
) && s
->nb_streams
> 0) {
308 /* get the control url */
309 st
= s
->streams
[s
->nb_streams
- 1];
310 rtsp_st
= st
->priv_data
;
312 /* XXX: may need to add full url resolution */
313 url_split(proto
, sizeof(proto
), NULL
, 0, NULL
, NULL
, 0, p
);
314 if (proto
[0] == '\0') {
315 /* relative control URL */
316 pstrcat(rtsp_st
->control_url
, sizeof(rtsp_st
->control_url
), "/");
317 pstrcat(rtsp_st
->control_url
, sizeof(rtsp_st
->control_url
), p
);
319 pstrcpy(rtsp_st
->control_url
, sizeof(rtsp_st
->control_url
), p
);
321 } else if (strstart(p
, "rtpmap:", &p
)) {
322 /* NOTE: rtpmap is only supported AFTER the 'm=' tag */
323 get_word(buf1
, sizeof(buf1
), &p
);
324 payload_type
= atoi(buf1
);
325 for(i
= 0; i
< s
->nb_streams
;i
++) {
327 rtsp_st
= st
->priv_data
;
328 if (rtsp_st
->sdp_payload_type
== payload_type
) {
329 sdp_parse_rtpmap(&st
->codec
, p
);
332 } else if (strstart(p
, "fmtp:", &p
)) {
333 /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */
334 get_word(buf1
, sizeof(buf1
), &p
);
335 payload_type
= atoi(buf1
);
336 for(i
= 0; i
< s
->nb_streams
;i
++) {
338 rtsp_st
= st
->priv_data
;
339 if (rtsp_st
->sdp_payload_type
== payload_type
) {
340 sdp_parse_fmtp(&st
->codec
, p
);
348 int sdp_parse(AVFormatContext
*s
, const char *content
)
353 SDPParseState sdp_parse_state
, *s1
= &sdp_parse_state
;
355 memset(s1
, 0, sizeof(SDPParseState
));
366 /* get the content */
368 while (*p
!= '\n' && *p
!= '\0') {
369 if ((q
- buf
) < sizeof(buf
) - 1)
374 sdp_parse_line(s
, s1
, letter
, buf
);
376 while (*p
!= '\n' && *p
!= '\0')
384 static void rtsp_parse_range(int *min_ptr
, int *max_ptr
, const char **pp
)
391 v
= strtol(p
, (char **)&p
, 10);
395 v
= strtol(p
, (char **)&p
, 10);
404 /* XXX: only one transport specification is parsed */
405 static void rtsp_parse_transport(RTSPHeader
*reply
, const char *p
)
407 char transport_protocol
[16];
409 char lower_transport
[16];
411 RTSPTransportField
*th
;
414 reply
->nb_transports
= 0;
421 th
= &reply
->transports
[reply
->nb_transports
];
423 get_word_sep(transport_protocol
, sizeof(transport_protocol
),
427 get_word_sep(profile
, sizeof(profile
), "/;,", &p
);
428 lower_transport
[0] = '\0';
430 get_word_sep(lower_transport
, sizeof(lower_transport
),
433 if (!strcmp(lower_transport
, "TCP"))
434 th
->protocol
= RTSP_PROTOCOL_RTP_TCP
;
436 th
->protocol
= RTSP_PROTOCOL_RTP_UDP
;
440 /* get each parameter */
441 while (*p
!= '\0' && *p
!= ',') {
442 get_word_sep(parameter
, sizeof(parameter
), "=;,", &p
);
443 if (!strcmp(parameter
, "port")) {
446 rtsp_parse_range(&th
->port_min
, &th
->port_max
, &p
);
448 } else if (!strcmp(parameter
, "client_port")) {
451 rtsp_parse_range(&th
->client_port_min
,
452 &th
->client_port_max
, &p
);
454 } else if (!strcmp(parameter
, "server_port")) {
457 rtsp_parse_range(&th
->server_port_min
,
458 &th
->server_port_max
, &p
);
460 } else if (!strcmp(parameter
, "interleaved")) {
463 rtsp_parse_range(&th
->interleaved_min
,
464 &th
->interleaved_max
, &p
);
466 } else if (!strcmp(parameter
, "multicast")) {
467 if (th
->protocol
== RTSP_PROTOCOL_RTP_UDP
)
468 th
->protocol
= RTSP_PROTOCOL_RTP_UDP_MULTICAST
;
469 } else if (!strcmp(parameter
, "ttl")) {
472 th
->ttl
= strtol(p
, (char **)&p
, 10);
474 } else if (!strcmp(parameter
, "destination")) {
475 struct in_addr ipaddr
;
479 get_word_sep(buf
, sizeof(buf
), ";,", &p
);
480 if (inet_aton(buf
, &ipaddr
))
481 th
->destination
= ntohl(ipaddr
.s_addr
);
484 while (*p
!= ';' && *p
!= '\0' && *p
!= ',')
492 reply
->nb_transports
++;
496 void rtsp_parse_line(RTSPHeader
*reply
, const char *buf
)
500 /* NOTE: we do case independent match for broken servers */
502 if (stristart(p
, "Session:", &p
)) {
503 get_word_sep(reply
->session_id
, sizeof(reply
->session_id
), ";", &p
);
504 } else if (stristart(p
, "Content-Length:", &p
)) {
505 reply
->content_length
= strtol(p
, NULL
, 10);
506 } else if (stristart(p
, "Transport:", &p
)) {
507 rtsp_parse_transport(reply
, p
);
508 } else if (stristart(p
, "CSeq:", &p
)) {
509 reply
->seq
= strtol(p
, NULL
, 10);
514 static void rtsp_send_cmd(AVFormatContext
*s
,
515 const char *cmd
, RTSPHeader
*reply
,
516 unsigned char **content_ptr
)
518 RTSPState
*rt
= s
->priv_data
;
519 char buf
[4096], buf1
[1024], *q
;
522 int content_length
, line_count
;
523 unsigned char *content
= NULL
;
525 memset(reply
, 0, sizeof(RTSPHeader
));
528 pstrcpy(buf
, sizeof(buf
), cmd
);
529 snprintf(buf1
, sizeof(buf1
), "CSeq: %d\n", rt
->seq
);
530 pstrcat(buf
, sizeof(buf
), buf1
);
531 if (rt
->session_id
[0] != '\0' && !strstr(cmd
, "\nIf-Match:")) {
532 snprintf(buf1
, sizeof(buf1
), "Session: %s\n", rt
->session_id
);
533 pstrcat(buf
, sizeof(buf
), buf1
);
535 pstrcat(buf
, sizeof(buf
), "\n");
537 printf("Sending:\n%s--\n", buf
);
539 url_write(rt
->rtsp_hd
, buf
, strlen(buf
));
541 /* parse reply (XXX: use buffers) */
543 rt
->last_reply
[0] = '\0';
547 if (url_read(rt
->rtsp_hd
, &ch
, 1) == 0)
552 if ((q
- buf
) < sizeof(buf
) - 1)
558 printf("line='%s'\n", buf
);
560 /* test if last line */
564 if (line_count
== 0) {
566 get_word(buf1
, sizeof(buf1
), &p
);
567 get_word(buf1
, sizeof(buf1
), &p
);
568 reply
->status_code
= atoi(buf1
);
570 rtsp_parse_line(reply
, p
);
571 pstrcat(rt
->last_reply
, sizeof(rt
->last_reply
), p
);
572 pstrcat(rt
->last_reply
, sizeof(rt
->last_reply
), "\n");
577 if (rt
->session_id
[0] == '\0' && reply
->session_id
[0] != '\0')
578 pstrcpy(rt
->session_id
, sizeof(rt
->session_id
), reply
->session_id
);
580 content_length
= reply
->content_length
;
581 if (content_length
> 0) {
582 /* leave some room for a trailing '\0' (useful for simple parsing) */
583 content
= av_malloc(content_length
+ 1);
584 url_read(rt
->rtsp_hd
, content
, content_length
);
585 content
[content_length
] = '\0';
588 *content_ptr
= content
;
591 /* useful for modules: set RTSP callback function */
593 void rtsp_set_callback(FFRTSPCallback
*rtsp_cb
)
595 ff_rtsp_callback
= rtsp_cb
;
599 static int rtsp_read_header(AVFormatContext
*s
,
600 AVFormatParameters
*ap
)
602 RTSPState
*rt
= s
->priv_data
;
603 char host
[1024], path
[1024], tcpname
[1024], cmd
[2048];
605 int port
, i
, ret
, err
;
606 RTSPHeader reply1
, *reply
= &reply1
;
607 unsigned char *content
= NULL
;
614 /* extract hostname and port */
616 host
, sizeof(host
), &port
, path
, sizeof(path
), s
->filename
);
618 port
= RTSP_DEFAULT_PORT
;
620 /* open the tcp connexion */
621 snprintf(tcpname
, sizeof(tcpname
), "tcp://%s:%d", host
, port
);
622 if (url_open(&rtsp_hd
, tcpname
, URL_RDWR
) < 0)
624 rt
->rtsp_hd
= rtsp_hd
;
627 /* describe the stream */
628 snprintf(cmd
, sizeof(cmd
),
629 "DESCRIBE %s RTSP/1.0\n"
630 "Accept: application/sdp\n",
632 rtsp_send_cmd(s
, cmd
, reply
, &content
);
634 err
= AVERROR_INVALIDDATA
;
637 if (reply
->status_code
!= RTSP_STATUS_OK
) {
638 err
= AVERROR_INVALIDDATA
;
642 /* now we got the SDP description, we parse it */
643 ret
= sdp_parse(s
, (const char *)content
);
646 err
= AVERROR_INVALIDDATA
;
650 protocol_mask
= rtsp_default_protocols
;
652 /* for each stream, make the setup request */
653 /* XXX: we assume the same server is used for the control of each
655 for(i
=0;i
<s
->nb_streams
;i
++) {
656 char transport
[2048];
660 rtsp_st
= st
->priv_data
;
662 /* compute available transports */
666 if (protocol_mask
& (1 << RTSP_PROTOCOL_RTP_UDP
)) {
670 /* first try in specified port range */
671 if (rtsp_rtp_port_min
!= 0) {
672 for(j
=rtsp_rtp_port_min
;j
<=rtsp_rtp_port_max
;j
++) {
673 snprintf(buf
, sizeof(buf
), "rtp://?localport=%d", j
);
674 if (!av_open_input_file(&rtsp_st
->ic
, buf
,
675 &rtp_demux
, 0, NULL
))
680 /* then try on any port */
681 if (av_open_input_file(&rtsp_st
->ic
, "rtp://",
682 &rtp_demux
, 0, NULL
) < 0) {
683 err
= AVERROR_INVALIDDATA
;
688 port
= rtp_get_local_port(url_fileno(&rtsp_st
->ic
->pb
));
689 if (transport
[0] != '\0')
690 pstrcat(transport
, sizeof(transport
), ",");
691 snprintf(transport
+ strlen(transport
), sizeof(transport
) - strlen(transport
) - 1,
692 "RTP/AVP/UDP;unicast;client_port=%d-%d",
697 if (protocol_mask
& (1 << RTSP_PROTOCOL_RTP_TCP
)) {
698 if (transport
[0] != '\0')
699 pstrcat(transport
, sizeof(transport
), ",");
700 snprintf(transport
+ strlen(transport
), sizeof(transport
) - strlen(transport
) - 1,
704 if (protocol_mask
& (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST
)) {
705 if (transport
[0] != '\0')
706 pstrcat(transport
, sizeof(transport
), ",");
707 snprintf(transport
+ strlen(transport
),
708 sizeof(transport
) - strlen(transport
) - 1,
709 "RTP/AVP/UDP;multicast");
712 snprintf(cmd
, sizeof(cmd
),
713 "SETUP %s RTSP/1.0\n"
715 rtsp_st
->control_url
, transport
);
716 rtsp_send_cmd(s
, cmd
, reply
, NULL
);
717 if (reply
->status_code
!= RTSP_STATUS_OK
||
718 reply
->nb_transports
!= 1) {
719 err
= AVERROR_INVALIDDATA
;
723 /* XXX: same protocol for all streams is required */
725 if (reply
->transports
[0].protocol
!= rt
->protocol
) {
726 err
= AVERROR_INVALIDDATA
;
730 rt
->protocol
= reply
->transports
[0].protocol
;
733 /* close RTP connection if not choosen */
734 if (reply
->transports
[0].protocol
!= RTSP_PROTOCOL_RTP_UDP
&&
735 (protocol_mask
& (1 << RTSP_PROTOCOL_RTP_UDP
))) {
736 av_close_input_file(rtsp_st
->ic
);
740 switch(reply
->transports
[0].protocol
) {
741 case RTSP_PROTOCOL_RTP_TCP
:
743 if (av_open_input_file(&rtsp_st
->ic
, "null", fmt
, 0, NULL
) < 0) {
744 err
= AVERROR_INVALIDDATA
;
747 rtsp_st
->interleaved_min
= reply
->transports
[0].interleaved_min
;
748 rtsp_st
->interleaved_max
= reply
->transports
[0].interleaved_max
;
751 case RTSP_PROTOCOL_RTP_UDP
:
755 /* XXX: also use address if specified */
756 snprintf(url
, sizeof(url
), "rtp://%s:%d",
757 host
, reply
->transports
[0].server_port_min
);
758 if (rtp_set_remote_url(url_fileno(&rtsp_st
->ic
->pb
), url
) < 0) {
759 err
= AVERROR_INVALIDDATA
;
764 case RTSP_PROTOCOL_RTP_UDP_MULTICAST
:
770 ttl
= reply
->transports
[0].ttl
;
773 snprintf(url
, sizeof(url
), "rtp://%s:%d?multicast=1&ttl=%d",
775 reply
->transports
[0].server_port_min
,
777 if (av_open_input_file(&rtsp_st
->ic
, url
, fmt
, 0, NULL
) < 0) {
778 err
= AVERROR_INVALIDDATA
;
786 /* use callback if available to extend setup */
787 if (ff_rtsp_callback
) {
788 if (ff_rtsp_callback(RTSP_ACTION_CLIENT_SETUP
, rt
->session_id
,
789 NULL
, 0, rt
->last_reply
) < 0) {
790 err
= AVERROR_INVALIDDATA
;
796 snprintf(cmd
, sizeof(cmd
),
797 "PLAY %s RTSP/1.0\n",
799 rtsp_send_cmd(s
, cmd
, reply
, NULL
);
800 if (reply
->status_code
!= RTSP_STATUS_OK
) {
801 err
= AVERROR_INVALIDDATA
;
805 /* open TCP with bufferized input */
806 if (rt
->protocol
== RTSP_PROTOCOL_RTP_TCP
) {
807 if (url_fdopen(&rt
->rtsp_gb
, rt
->rtsp_hd
) < 0) {
815 for(i
=0;i
<s
->nb_streams
;i
++) {
817 rtsp_st
= st
->priv_data
;
820 av_close_input_file(rtsp_st
->ic
);
825 url_close(rt
->rtsp_hd
);
829 static int tcp_read_packet(AVFormatContext
*s
,
832 RTSPState
*rt
= s
->priv_data
;
833 ByteIOContext
*rtsp_gb
= &rt
->rtsp_gb
;
834 int c
, id
, len
, i
, ret
;
837 char buf
[RTP_MAX_PACKET_LENGTH
];
841 c
= url_fgetc(rtsp_gb
);
847 id
= get_byte(rtsp_gb
);
848 len
= get_be16(rtsp_gb
);
849 if (len
> RTP_MAX_PACKET_LENGTH
|| len
< 12)
852 get_buffer(rtsp_gb
, buf
, len
);
854 /* find the matching stream */
855 for(i
= 0; i
< s
->nb_streams
; i
++) {
857 rtsp_st
= st
->priv_data
;
858 if (i
>= rtsp_st
->interleaved_min
&&
859 i
<= rtsp_st
->interleaved_max
)
864 ret
= rtp_parse_packet(rtsp_st
->ic
, pkt
, buf
, len
);
867 pkt
->stream_index
= i
;
871 /* NOTE: output one packet at a time. May need to add a small fifo */
872 static int udp_read_packet(AVFormatContext
*s
,
879 int fd1
, fd2
, fd_max
, n
, i
, ret
;
880 char buf
[RTP_MAX_PACKET_LENGTH
];
888 for(i
= 0; i
< s
->nb_streams
; i
++) {
890 rtsp_st
= st
->priv_data
;
892 /* currently, we cannot probe RTCP handle because of blocking restrictions */
893 rtp_get_file_handles(url_fileno(&ic
->pb
), &fd1
, &fd2
);
898 /* XXX: also add proper API to abort */
901 n
= select(fd_max
+ 1, &rfds
, NULL
, NULL
, &tv
);
903 for(i
= 0; i
< s
->nb_streams
; i
++) {
905 rtsp_st
= st
->priv_data
;
907 rtp_get_file_handles(url_fileno(&ic
->pb
), &fd1
, &fd2
);
908 if (FD_ISSET(fd1
, &rfds
)) {
909 ret
= url_read(url_fileno(&ic
->pb
), buf
, sizeof(buf
));
911 rtp_parse_packet(ic
, pkt
, buf
, ret
) == 0) {
912 pkt
->stream_index
= i
;
921 static int rtsp_read_packet(AVFormatContext
*s
,
924 RTSPState
*rt
= s
->priv_data
;
927 switch(rt
->protocol
) {
929 case RTSP_PROTOCOL_RTP_TCP
:
930 ret
= tcp_read_packet(s
, pkt
);
932 case RTSP_PROTOCOL_RTP_UDP
:
933 ret
= udp_read_packet(s
, pkt
);
939 static int rtsp_read_close(AVFormatContext
*s
)
941 RTSPState
*rt
= s
->priv_data
;
944 RTSPHeader reply1
, *reply
= &reply1
;
948 /* NOTE: it is valid to flush the buffer here */
949 if (rt
->protocol
== RTSP_PROTOCOL_RTP_TCP
) {
950 url_fclose(&rt
->rtsp_gb
);
953 snprintf(cmd
, sizeof(cmd
),
954 "TEARDOWN %s RTSP/1.0\n",
956 rtsp_send_cmd(s
, cmd
, reply
, NULL
);
958 if (ff_rtsp_callback
) {
959 ff_rtsp_callback(RTSP_ACTION_CLIENT_TEARDOWN
, rt
->session_id
,
963 for(i
=0;i
<s
->nb_streams
;i
++) {
965 rtsp_st
= st
->priv_data
;
968 av_close_input_file(rtsp_st
->ic
);
972 url_close(rt
->rtsp_hd
);
976 static AVInputFormat rtsp_demux
= {
984 .flags
= AVFMT_NOFILE
,
988 /* XXX: add mime type support */
989 static int sdp_probe(AVProbeData
*p
)
991 if (match_ext(p
->filename
, "sdp"))
992 return AVPROBE_SCORE_MAX
;
996 #define SDP_MAX_SIZE 8192
998 static int sdp_read_header(AVFormatContext
*s
,
999 AVFormatParameters
*ap
)
1002 RTSPStream
*rtsp_st
;
1007 /* read the whole sdp file */
1008 /* XXX: better loading */
1009 content
= av_malloc(SDP_MAX_SIZE
);
1010 size
= get_buffer(&s
->pb
, content
, SDP_MAX_SIZE
- 1);
1013 return AVERROR_INVALIDDATA
;
1015 content
[size
] ='\0';
1017 sdp_parse(s
, content
);
1020 /* open each RTP stream */
1021 for(i
=0;i
<s
->nb_streams
;i
++) {
1023 rtsp_st
= st
->priv_data
;
1025 snprintf(url
, sizeof(url
), "rtp://%s:%d?multicast=1&ttl=%d",
1026 inet_ntoa(rtsp_st
->sdp_ip
),
1029 if (av_open_input_file(&rtsp_st
->ic
, url
, &rtp_demux
, 0, NULL
) < 0) {
1030 err
= AVERROR_INVALIDDATA
;
1036 for(i
=0;i
<s
->nb_streams
;i
++) {
1038 rtsp_st
= st
->priv_data
;
1041 av_close_input_file(rtsp_st
->ic
);
1048 static int sdp_read_packet(AVFormatContext
*s
,
1051 return udp_read_packet(s
, pkt
);
1054 static int sdp_read_close(AVFormatContext
*s
)
1057 RTSPStream
*rtsp_st
;
1060 for(i
=0;i
<s
->nb_streams
;i
++) {
1062 rtsp_st
= st
->priv_data
;
1065 av_close_input_file(rtsp_st
->ic
);
1073 static AVInputFormat sdp_demux
= {
1084 /* dummy redirector format (used directly in av_open_input_file now) */
1085 static int redir_probe(AVProbeData
*pd
)
1089 while (redir_isspace(*p
))
1091 if (strstart(p
, "http://", NULL
) ||
1092 strstart(p
, "rtsp://", NULL
))
1093 return AVPROBE_SCORE_MAX
;
1097 /* called from utils.c */
1098 int redir_open(AVFormatContext
**ic_ptr
, ByteIOContext
*f
)
1102 AVFormatContext
*ic
= NULL
;
1104 /* parse each URL and try to open it */
1106 while (c
!= URL_EOF
) {
1109 if (!redir_isspace(c
))
1118 if (c
== URL_EOF
|| redir_isspace(c
))
1120 if ((q
- buf
) < sizeof(buf
) - 1)
1125 //printf("URL='%s'\n", buf);
1126 /* try to open the media file */
1127 if (av_open_input_file(&ic
, buf
, NULL
, 0, NULL
) == 0)
1137 AVInputFormat redir_demux
= {
1139 "Redirector format",
1149 av_register_input_format(&rtsp_demux
);
1150 av_register_input_format(&redir_demux
);
1151 av_register_input_format(&sdp_demux
);