diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2013-01-09 11:48:14 +0100 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2013-01-09 11:48:14 +0100 |
commit | 34c1c08c665389daa190cb331e4d899da8dde57a (patch) | |
tree | 4102f99b0b4cc834d0b9b6ccaef586753ad9c0f0 /libavformat | |
parent | 8c3ae9ee66a2fb094b188c994a18df9f3e69a283 (diff) | |
parent | 86d9181cf41edc3382bf2481f95a2fb321058689 (diff) | |
download | ffmpeg-34c1c08c665389daa190cb331e4d899da8dde57a.tar.gz |
Merge commit '86d9181cf41edc3382bf2481f95a2fb321058689'
* commit '86d9181cf41edc3382bf2481f95a2fb321058689':
rtpdec: Support sending RTCP feedback packets
Conflicts:
libavformat/version.h
Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/rtpdec.c | 96 | ||||
-rw-r--r-- | libavformat/rtpdec.h | 5 | ||||
-rw-r--r-- | libavformat/rtsp.c | 8 | ||||
-rw-r--r-- | libavformat/rtsp.h | 3 | ||||
-rw-r--r-- | libavformat/version.h | 2 |
5 files changed, 113 insertions, 1 deletions
diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c index 1ffa4e0975..6079d9a226 100644 --- a/libavformat/rtpdec.c +++ b/libavformat/rtpdec.c @@ -30,6 +30,8 @@ #include "rtpdec.h" #include "rtpdec_formats.h" +#define MIN_FEEDBACK_INTERVAL 200000 /* 200 ms in us */ + static RTPDynamicProtocolHandler realmedia_mp3_dynamic_handler = { .enc_name = "X-MP3-draft-00", .codec_type = AVMEDIA_TYPE_AUDIO, @@ -366,6 +368,100 @@ void ff_rtp_send_punch_packets(URLContext *rtp_handle) av_free(buf); } +static int find_missing_packets(RTPDemuxContext *s, uint16_t *first_missing, + uint16_t *missing_mask) +{ + int i; + uint16_t next_seq = s->seq + 1; + RTPPacket *pkt = s->queue; + + if (!pkt || pkt->seq == next_seq) + return 0; + + *missing_mask = 0; + for (i = 1; i <= 16; i++) { + uint16_t missing_seq = next_seq + i; + while (pkt) { + int16_t diff = pkt->seq - missing_seq; + if (diff >= 0) + break; + pkt = pkt->next; + } + if (!pkt) + break; + if (pkt->seq == missing_seq) + continue; + *missing_mask |= 1 << (i - 1); + } + + *first_missing = next_seq; + return 1; +} + +int ff_rtp_send_rtcp_feedback(RTPDemuxContext *s, URLContext *fd, + AVIOContext *avio) +{ + int len, need_keyframe, missing_packets; + AVIOContext *pb; + uint8_t *buf; + int64_t now; + uint16_t first_missing, missing_mask; + + if (!fd && !avio) + return -1; + + need_keyframe = s->handler && s->handler->need_keyframe && + s->handler->need_keyframe(s->dynamic_protocol_context); + missing_packets = find_missing_packets(s, &first_missing, &missing_mask); + + if (!need_keyframe && !missing_packets) + return 0; + + /* Send new feedback if enough time has elapsed since the last + * feedback packet. */ + + now = av_gettime(); + if (s->last_feedback_time && + (now - s->last_feedback_time) < MIN_FEEDBACK_INTERVAL) + return 0; + s->last_feedback_time = now; + + if (!fd) + pb = avio; + else if (avio_open_dyn_buf(&pb) < 0) + return -1; + + if (need_keyframe) { + avio_w8(pb, (RTP_VERSION << 6) | 1); /* PLI */ + avio_w8(pb, RTCP_PSFB); + avio_wb16(pb, 2); /* length in words - 1 */ + // our own SSRC: we use the server's SSRC + 1 to avoid conflicts + avio_wb32(pb, s->ssrc + 1); + avio_wb32(pb, s->ssrc); // server SSRC + } + + if (missing_packets) { + avio_w8(pb, (RTP_VERSION << 6) | 1); /* NACK */ + avio_w8(pb, RTCP_RTPFB); + avio_wb16(pb, 3); /* length in words - 1 */ + avio_wb32(pb, s->ssrc + 1); + avio_wb32(pb, s->ssrc); // server SSRC + + avio_wb16(pb, first_missing); + avio_wb16(pb, missing_mask); + } + + avio_flush(pb); + if (!fd) + return 0; + len = avio_close_dyn_buf(pb, &buf); + if (len > 0 && buf) { + ffurl_write(fd, buf, len); + av_free(buf); + } + return 0; +} + /** * open a new RTP parse context for stream 'st'. 'st' can be NULL for * MPEG2-TS streams to indicate that they should be demuxed inside the diff --git a/libavformat/rtpdec.h b/libavformat/rtpdec.h index 3023cee8bf..b8eb2f9f1c 100644 --- a/libavformat/rtpdec.h +++ b/libavformat/rtpdec.h @@ -73,6 +73,8 @@ void ff_rtp_send_punch_packets(URLContext* rtp_handle); */ int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, URLContext *fd, AVIOContext *avio, int count); +int ff_rtp_send_rtcp_feedback(RTPDemuxContext *s, URLContext *fd, + AVIOContext *avio); // these statistics are used for rtcp receiver reports... typedef struct RTPStatistics { @@ -130,6 +132,7 @@ struct RTPDynamicProtocolHandler { void (*free)(PayloadContext *protocol_data); /** Parse handler for this dynamic packet */ DynamicPayloadPacketHandlerProc parse_packet; + int (*need_keyframe)(PayloadContext *context); struct RTPDynamicProtocolHandler *next; }; @@ -180,6 +183,8 @@ struct RTPDemuxContext { unsigned int packet_count; unsigned int octet_count; unsigned int last_octet_count; + int64_t last_feedback_time; + /* buffer for partially parsed packets */ uint8_t buf[RTP_MAX_PACKET_LENGTH]; diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 9aae845b35..dcd5085310 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -380,6 +380,8 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, get_word(buf1, sizeof(buf1), &p); /* protocol */ if (!strcmp(buf1, "udp")) rt->transport = RTSP_TRANSPORT_RAW; + else if (strstr(buf1, "/AVPF") || strstr(buf1, "/SAVPF")) + rtsp_st->feedback = 1; /* XXX: handle list of formats */ get_word(buf1, sizeof(buf1), &p); /* format list */ @@ -1932,6 +1934,12 @@ redo: ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len); } else if (rt->transport == RTSP_TRANSPORT_RTP) { ret = ff_rtp_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len); + if (rtsp_st->feedback) { + AVIOContext *pb = NULL; + if (rt->lower_transport == RTSP_LOWER_TRANSPORT_CUSTOM) + pb = s->pb; + ff_rtp_send_rtcp_feedback(rtsp_st->transport_priv, rtsp_st->rtp_handle, pb); + } if (ret < 0) { /* Either bad packet, or a RTCP packet. Check if the * first_rtcp_ntp_time field was initialized. */ diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h index 7ca8f64569..fb4c761495 100644 --- a/libavformat/rtsp.h +++ b/libavformat/rtsp.h @@ -437,6 +437,9 @@ typedef struct RTSPStream { /** private data associated with the dynamic protocol */ PayloadContext *dynamic_protocol_context; //@} + + /** Enable sending RTCP feedback messages according to RFC 4585 */ + int feedback; } RTSPStream; void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf, diff --git a/libavformat/version.h b/libavformat/version.h index 49cd01a9d8..e50e501462 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,7 +31,7 @@ #define LIBAVFORMAT_VERSION_MAJOR 54 #define LIBAVFORMAT_VERSION_MINOR 59 -#define LIBAVFORMAT_VERSION_MICRO 106 +#define LIBAVFORMAT_VERSION_MICRO 107 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ |