diff options
author | Martin Storsjö <martin@martin.st> | 2010-10-19 07:38:53 +0000 |
---|---|---|
committer | Martin Storsjö <martin@martin.st> | 2010-10-19 07:38:53 +0000 |
commit | 44594cc7980a4651aba8ac40c59192c283634748 (patch) | |
tree | 2c7b16f9124a68bc1b09429f5d122475553b3613 /libavformat/rtsp.c | |
parent | 4ad08021e8e81057d89c75fd63b97cd1f0757a23 (diff) | |
download | ffmpeg-44594cc7980a4651aba8ac40c59192c283634748.tar.gz |
Add a demuxer for receiving raw rtp:// URLs without an SDP description
The demuxer inspects the payload type of a received RTP packet and
handles the cases where the content is fully described by the payload type.
Originally committed as revision 25527 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavformat/rtsp.c')
-rw-r--r-- | libavformat/rtsp.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 6570c3880b..aff745a370 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -2104,3 +2104,107 @@ AVInputFormat sdp_demuxer = { rtsp_fetch_packet, sdp_read_close, }; + +static int rtp_probe(AVProbeData *p) +{ + if (av_strstart(p->filename, "rtp:", NULL)) + return AVPROBE_SCORE_MAX; + return 0; +} + +static int rtp_read_header(AVFormatContext *s, + AVFormatParameters *ap) +{ + uint8_t recvbuf[1500]; + char host[500], sdp[500]; + int ret, port; + URLContext* in = NULL; + int payload_type; + AVCodecContext codec; + struct sockaddr_storage addr; + ByteIOContext pb; + socklen_t addrlen = sizeof(addr); + + if (!ff_network_init()) + return AVERROR(EIO); + + ret = url_open(&in, s->filename, URL_RDONLY); + if (ret) + goto fail; + + while (1) { + ret = url_read(in, recvbuf, sizeof(recvbuf)); + if (ret == AVERROR(EAGAIN)) + continue; + if (ret < 0) + goto fail; + if (ret < 12) { + av_log(s, AV_LOG_WARNING, "Received too short packet\n"); + continue; + } + + if ((recvbuf[0] & 0xc0) != 0x80) { + av_log(s, AV_LOG_WARNING, "Unsupported RTP version packet " + "received\n"); + continue; + } + + payload_type = recvbuf[1] & 0x7f; + break; + } + getsockname(url_get_file_handle(in), (struct sockaddr*) &addr, &addrlen); + url_close(in); + in = NULL; + + memset(&codec, 0, sizeof(codec)); + if (ff_rtp_get_codec_info(&codec, payload_type)) { + av_log(s, AV_LOG_ERROR, "Unable to receive RTP payload type %d " + "without an SDP file describing it\n", + payload_type); + goto fail; + } + if (codec.codec_type != AVMEDIA_TYPE_DATA) { + av_log(s, AV_LOG_WARNING, "Guessing on RTP content - if not received " + "properly you need an SDP file " + "describing it\n"); + } + + av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, + NULL, 0, s->filename); + + snprintf(sdp, sizeof(sdp), + "v=0\r\nc=IN IP%d %s\r\nm=%s %d RTP/AVP %d\r\n", + addr.ss_family == AF_INET ? 4 : 6, host, + codec.codec_type == AVMEDIA_TYPE_DATA ? "application" : + codec.codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio", + port, payload_type); + av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", sdp); + + init_put_byte(&pb, sdp, strlen(sdp), 0, NULL, NULL, NULL, NULL); + s->pb = &pb; + + /* sdp_read_header initializes this again */ + ff_network_close(); + + ret = sdp_read_header(s, ap); + s->pb = NULL; + return ret; + +fail: + if (in) + url_close(in); + ff_network_close(); + return ret; +} + +AVInputFormat rtp_demuxer = { + "rtp", + NULL_IF_CONFIG_SMALL("RTP input format"), + sizeof(RTSPState), + rtp_probe, + rtp_read_header, + rtsp_fetch_packet, + sdp_read_close, + .flags = AVFMT_NOFILE, +}; + |