diff options
author | Martin Storsjö | 2013-01-01 23:41:29 +0200 |
---|---|---|
committer | Martin Storsjö | 2013-01-03 15:15:27 +0200 |
commit | e96406eda4f143f101bd44372f7b2d542183000a (patch) | |
tree | 736ef477e160701b05627f562bb533c83f0e26a5 | |
parent | 3f95f0dda55fca74b646937095a02a8fa9776622 (diff) |
rtsp: Add support for depacketizing RTP data via custom IO
To use this, set sdpflags=custom_io to the sdp demuxer. During
the avformat_open_input call, the SDP is read from the AVFormatContext
AVIOContext (ctx->pb) - after the avformat_open_input call,
during the av_read_frame() calls, the same ctx->pb is used for reading
packets (and sending back RTCP RR packets).
Normally, one would use this with a read-only AVIOContext for the
SDP during the avformat_open_input call, then close that one and
replace it with a read-write one for the packets after the
avformat_open_input call has returned.
This allows using the RTP depacketizers as "pure" demuxers, without
having them tied to the libavformat network IO.
Signed-off-by: Martin Storsjö <martin@martin.st>
-rw-r--r-- | libavformat/rtpdec.c | 11 | ||||
-rw-r--r-- | libavformat/rtpdec.h | 5 | ||||
-rw-r--r-- | libavformat/rtsp.c | 79 | ||||
-rw-r--r-- | libavformat/rtsp.h | 5 | ||||
-rw-r--r-- | libavformat/version.h | 2 |
5 files changed, 84 insertions, 18 deletions
diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c index 77df188cb9..08150b734a 100644 --- a/libavformat/rtpdec.c +++ b/libavformat/rtpdec.c @@ -226,7 +226,8 @@ static int rtp_valid_packet_in_sequence(RTPStatistics *s, uint16_t seq) return 1; } -int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, URLContext *fd, int count) +int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, URLContext *fd, + AVIOContext *avio, int count) { AVIOContext *pb; uint8_t *buf; @@ -242,7 +243,7 @@ int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, URLContext *fd, int count) uint32_t fraction; uint64_t ntp_time = s->last_rtcp_ntp_time; // TODO: Get local ntp time? - if (!fd || (count < 1)) + if ((!fd && !avio) || (count < 1)) return -1; /* TODO: I think this is way too often; RFC 1889 has algorithm for this */ @@ -255,7 +256,9 @@ int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, URLContext *fd, int count) return -1; s->last_octet_count = s->octet_count; - if (avio_open_dyn_buf(&pb) < 0) + if (!fd) + pb = avio; + else if (avio_open_dyn_buf(&pb) < 0) return -1; // Receiver Report @@ -312,6 +315,8 @@ int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, URLContext *fd, int count) avio_w8(pb, 0); avio_flush(pb); + if (!fd) + return 0; len = avio_close_dyn_buf(pb, &buf); if ((len > 0) && buf) { int av_unused result; diff --git a/libavformat/rtpdec.h b/libavformat/rtpdec.h index 2d962c82c7..7c51f5a8d2 100644 --- a/libavformat/rtpdec.h +++ b/libavformat/rtpdec.h @@ -68,10 +68,11 @@ void ff_rtp_send_punch_packets(URLContext* rtp_handle); /** * some rtp servers assume client is dead if they don't hear from them... - * so we send a Receiver Report to the provided URLContext + * so we send a Receiver Report to the provided URLContext or AVIOContext * (we don't have access to the rtcp handle from here) */ -int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, URLContext *fd, int count); +int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, URLContext *fd, + AVIOContext *avio, int count); // these statistics are used for rtcp receiver reports... typedef struct RTPStatistics { diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index d5b3242da4..134b3223e4 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -96,6 +96,7 @@ const AVOption ff_rtsp_options[] = { static const AVOption sdp_options[] = { RTSP_FLAG_OPTS("sdp_flags", "SDP flags"), + { "custom_io", "Use custom IO", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_CUSTOM_IO}, 0, 0, DEC, "rtsp_flags" }, RTSP_MEDIATYPE_OPTS("allowed_media_types", "Media types to accept from the server"), RTSP_REORDERING_OPTS(), { NULL }, @@ -1789,6 +1790,50 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, } } +static int pick_stream(AVFormatContext *s, RTSPStream **rtsp_st, + const uint8_t *buf, int len) +{ + RTSPState *rt = s->priv_data; + int i; + if (len < 0) + return len; + if (rt->nb_rtsp_streams == 1) { + *rtsp_st = rt->rtsp_streams[0]; + return len; + } + if (len >= 8 && rt->transport == RTSP_TRANSPORT_RTP) { + if (RTP_PT_IS_RTCP(rt->recvbuf[1])) { + int no_ssrc = 0; + for (i = 0; i < rt->nb_rtsp_streams; i++) { + RTPDemuxContext *rtpctx = rt->rtsp_streams[i]->transport_priv; + if (!rtpctx) + continue; + if (rtpctx->ssrc == AV_RB32(&buf[4])) { + *rtsp_st = rt->rtsp_streams[i]; + return len; + } + if (!rtpctx->ssrc) + no_ssrc = 1; + } + if (no_ssrc) { + av_log(s, AV_LOG_WARNING, + "Unable to pick stream for packet - SSRC not known for " + "all streams\n"); + return AVERROR(EAGAIN); + } + } else { + for (i = 0; i < rt->nb_rtsp_streams; i++) { + if ((buf[1] & 0x7f) == rt->rtsp_streams[i]->sdp_payload_type) { + *rtsp_st = rt->rtsp_streams[i]; + return len; + } + } + } + } + av_log(s, AV_LOG_WARNING, "Unable to pick stream for packet\n"); + return AVERROR(EAGAIN); +} + int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt) { RTSPState *rt = s->priv_data; @@ -1860,7 +1905,13 @@ int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt) case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: len = udp_read_packet(s, &rtsp_st, rt->recvbuf, RECVBUF_SIZE, wait_end); if (len > 0 && rtsp_st->transport_priv && rt->transport == RTSP_TRANSPORT_RTP) - ff_rtp_check_and_send_back_rr(rtsp_st->transport_priv, rtsp_st->rtp_handle, len); + ff_rtp_check_and_send_back_rr(rtsp_st->transport_priv, rtsp_st->rtp_handle, NULL, len); + break; + case RTSP_LOWER_TRANSPORT_CUSTOM: + len = ffio_read_partial(s->pb, rt->recvbuf, RECVBUF_SIZE); + len = pick_stream(s, &rtsp_st, rt->recvbuf, len); + if (len > 0 && rtsp_st->transport_priv && rt->transport == RTSP_TRANSPORT_RTP) + ff_rtp_check_and_send_back_rr(rtsp_st->transport_priv, NULL, s->pb, len); break; } if (len == AVERROR(EAGAIN) && first_queue_st && @@ -1973,6 +2024,8 @@ static int sdp_read_header(AVFormatContext *s) if (s->max_delay < 0) /* Not set by the caller */ s->max_delay = DEFAULT_REORDERING_DELAY; + if (rt->rtsp_flags & RTSP_FLAG_CUSTOM_IO) + rt->lower_transport = RTSP_LOWER_TRANSPORT_CUSTOM; /* read the whole sdp file */ /* XXX: better loading */ @@ -1993,17 +2046,19 @@ static int sdp_read_header(AVFormatContext *s) char namebuf[50]; rtsp_st = rt->rtsp_streams[i]; - getnameinfo((struct sockaddr*) &rtsp_st->sdp_ip, sizeof(rtsp_st->sdp_ip), - namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST); - ff_url_join(url, sizeof(url), "rtp", NULL, - namebuf, rtsp_st->sdp_port, - "?localport=%d&ttl=%d&connect=%d", rtsp_st->sdp_port, - rtsp_st->sdp_ttl, - rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0); - if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE, - &s->interrupt_callback, NULL) < 0) { - err = AVERROR_INVALIDDATA; - goto fail; + if (!(rt->rtsp_flags & RTSP_FLAG_CUSTOM_IO)) { + getnameinfo((struct sockaddr*) &rtsp_st->sdp_ip, sizeof(rtsp_st->sdp_ip), + namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST); + ff_url_join(url, sizeof(url), "rtp", NULL, + namebuf, rtsp_st->sdp_port, + "?localport=%d&ttl=%d&connect=%d", rtsp_st->sdp_port, + rtsp_st->sdp_ttl, + rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0); + if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE, + &s->interrupt_callback, NULL) < 0) { + err = AVERROR_INVALIDDATA; + goto fail; + } } if ((err = ff_rtsp_open_transport_ctx(s, rtsp_st))) goto fail; diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h index 043b67aa6f..3260f6c92d 100644 --- a/libavformat/rtsp.h +++ b/libavformat/rtsp.h @@ -42,6 +42,10 @@ enum RTSPLowerTransport { RTSP_LOWER_TRANSPORT_HTTP = 8, /**< HTTP tunneled - not a proper transport mode as such, only for use via AVOptions */ + RTSP_LOWER_TRANSPORT_CUSTOM = 16, /**< Custom IO - not a public + option for lower_transport_mask, + but set in the SDP demuxer based + on a flag. */ }; /** @@ -396,6 +400,7 @@ typedef struct RTSPState { receive packets only from the right source address and port. */ #define RTSP_FLAG_LISTEN 0x2 /**< Wait for incoming connections. */ +#define RTSP_FLAG_CUSTOM_IO 0x4 /**< Do all IO via the AVIOContext. */ /** * Describe a single stream, as identified by a single m= line block in the diff --git a/libavformat/version.h b/libavformat/version.h index 89af0bac6e..c2c1e3a8d6 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,7 +31,7 @@ #define LIBAVFORMAT_VERSION_MAJOR 54 #define LIBAVFORMAT_VERSION_MINOR 20 -#define LIBAVFORMAT_VERSION_MICRO 2 +#define LIBAVFORMAT_VERSION_MICRO 3 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ |