You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-07-11 14:30:22 +02:00
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>
This commit is contained in:
@ -226,7 +226,8 @@ static int rtp_valid_packet_in_sequence(RTPStatistics *s, uint16_t seq)
|
|||||||
return 1;
|
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;
|
AVIOContext *pb;
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
@ -242,7 +243,7 @@ int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, URLContext *fd, int count)
|
|||||||
uint32_t fraction;
|
uint32_t fraction;
|
||||||
uint64_t ntp_time = s->last_rtcp_ntp_time; // TODO: Get local ntp time?
|
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;
|
return -1;
|
||||||
|
|
||||||
/* TODO: I think this is way too often; RFC 1889 has algorithm for this */
|
/* 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;
|
return -1;
|
||||||
s->last_octet_count = s->octet_count;
|
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;
|
return -1;
|
||||||
|
|
||||||
// Receiver Report
|
// 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_w8(pb, 0);
|
||||||
|
|
||||||
avio_flush(pb);
|
avio_flush(pb);
|
||||||
|
if (!fd)
|
||||||
|
return 0;
|
||||||
len = avio_close_dyn_buf(pb, &buf);
|
len = avio_close_dyn_buf(pb, &buf);
|
||||||
if ((len > 0) && buf) {
|
if ((len > 0) && buf) {
|
||||||
int av_unused result;
|
int av_unused result;
|
||||||
|
@ -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...
|
* 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)
|
* (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...
|
// these statistics are used for rtcp receiver reports...
|
||||||
typedef struct RTPStatistics {
|
typedef struct RTPStatistics {
|
||||||
|
@ -96,6 +96,7 @@ const AVOption ff_rtsp_options[] = {
|
|||||||
|
|
||||||
static const AVOption sdp_options[] = {
|
static const AVOption sdp_options[] = {
|
||||||
RTSP_FLAG_OPTS("sdp_flags", "SDP flags"),
|
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_MEDIATYPE_OPTS("allowed_media_types", "Media types to accept from the server"),
|
||||||
RTSP_REORDERING_OPTS(),
|
RTSP_REORDERING_OPTS(),
|
||||||
{ NULL },
|
{ 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)
|
int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
|
||||||
{
|
{
|
||||||
RTSPState *rt = s->priv_data;
|
RTSPState *rt = s->priv_data;
|
||||||
@ -1860,7 +1905,13 @@ int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
|
case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
|
||||||
len = udp_read_packet(s, &rtsp_st, rt->recvbuf, RECVBUF_SIZE, wait_end);
|
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)
|
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;
|
break;
|
||||||
}
|
}
|
||||||
if (len == AVERROR(EAGAIN) && first_queue_st &&
|
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 */
|
if (s->max_delay < 0) /* Not set by the caller */
|
||||||
s->max_delay = DEFAULT_REORDERING_DELAY;
|
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 */
|
/* read the whole sdp file */
|
||||||
/* XXX: better loading */
|
/* XXX: better loading */
|
||||||
@ -1993,6 +2046,7 @@ static int sdp_read_header(AVFormatContext *s)
|
|||||||
char namebuf[50];
|
char namebuf[50];
|
||||||
rtsp_st = rt->rtsp_streams[i];
|
rtsp_st = rt->rtsp_streams[i];
|
||||||
|
|
||||||
|
if (!(rt->rtsp_flags & RTSP_FLAG_CUSTOM_IO)) {
|
||||||
getnameinfo((struct sockaddr*) &rtsp_st->sdp_ip, sizeof(rtsp_st->sdp_ip),
|
getnameinfo((struct sockaddr*) &rtsp_st->sdp_ip, sizeof(rtsp_st->sdp_ip),
|
||||||
namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
|
namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
|
||||||
ff_url_join(url, sizeof(url), "rtp", NULL,
|
ff_url_join(url, sizeof(url), "rtp", NULL,
|
||||||
@ -2005,6 +2059,7 @@ static int sdp_read_header(AVFormatContext *s)
|
|||||||
err = AVERROR_INVALIDDATA;
|
err = AVERROR_INVALIDDATA;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if ((err = ff_rtsp_open_transport_ctx(s, rtsp_st)))
|
if ((err = ff_rtsp_open_transport_ctx(s, rtsp_st)))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,10 @@ enum RTSPLowerTransport {
|
|||||||
RTSP_LOWER_TRANSPORT_HTTP = 8, /**< HTTP tunneled - not a proper
|
RTSP_LOWER_TRANSPORT_HTTP = 8, /**< HTTP tunneled - not a proper
|
||||||
transport mode as such,
|
transport mode as such,
|
||||||
only for use via AVOptions */
|
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
|
receive packets only from the right
|
||||||
source address and port. */
|
source address and port. */
|
||||||
#define RTSP_FLAG_LISTEN 0x2 /**< Wait for incoming connections. */
|
#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
|
* Describe a single stream, as identified by a single m= line block in the
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
#define LIBAVFORMAT_VERSION_MAJOR 54
|
#define LIBAVFORMAT_VERSION_MAJOR 54
|
||||||
#define LIBAVFORMAT_VERSION_MINOR 20
|
#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, \
|
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
||||||
LIBAVFORMAT_VERSION_MINOR, \
|
LIBAVFORMAT_VERSION_MINOR, \
|
||||||
|
Reference in New Issue
Block a user