mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-04-14 00:58:38 +02:00
Merge commit '86d9181cf41edc3382bf2481f95a2fb321058689'
* commit '86d9181cf41edc3382bf2481f95a2fb321058689': rtpdec: Support sending RTCP feedback packets Conflicts: libavformat/version.h Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
commit
34c1c08c66
@ -30,6 +30,8 @@
|
|||||||
#include "rtpdec.h"
|
#include "rtpdec.h"
|
||||||
#include "rtpdec_formats.h"
|
#include "rtpdec_formats.h"
|
||||||
|
|
||||||
|
#define MIN_FEEDBACK_INTERVAL 200000 /* 200 ms in us */
|
||||||
|
|
||||||
static RTPDynamicProtocolHandler realmedia_mp3_dynamic_handler = {
|
static RTPDynamicProtocolHandler realmedia_mp3_dynamic_handler = {
|
||||||
.enc_name = "X-MP3-draft-00",
|
.enc_name = "X-MP3-draft-00",
|
||||||
.codec_type = AVMEDIA_TYPE_AUDIO,
|
.codec_type = AVMEDIA_TYPE_AUDIO,
|
||||||
@ -366,6 +368,100 @@ void ff_rtp_send_punch_packets(URLContext *rtp_handle)
|
|||||||
av_free(buf);
|
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
|
* 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
|
* MPEG2-TS streams to indicate that they should be demuxed inside the
|
||||||
|
@ -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,
|
int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, URLContext *fd,
|
||||||
AVIOContext *avio, int count);
|
AVIOContext *avio, int count);
|
||||||
|
int ff_rtp_send_rtcp_feedback(RTPDemuxContext *s, URLContext *fd,
|
||||||
|
AVIOContext *avio);
|
||||||
|
|
||||||
// these statistics are used for rtcp receiver reports...
|
// these statistics are used for rtcp receiver reports...
|
||||||
typedef struct RTPStatistics {
|
typedef struct RTPStatistics {
|
||||||
@ -130,6 +132,7 @@ struct RTPDynamicProtocolHandler {
|
|||||||
void (*free)(PayloadContext *protocol_data);
|
void (*free)(PayloadContext *protocol_data);
|
||||||
/** Parse handler for this dynamic packet */
|
/** Parse handler for this dynamic packet */
|
||||||
DynamicPayloadPacketHandlerProc parse_packet;
|
DynamicPayloadPacketHandlerProc parse_packet;
|
||||||
|
int (*need_keyframe)(PayloadContext *context);
|
||||||
|
|
||||||
struct RTPDynamicProtocolHandler *next;
|
struct RTPDynamicProtocolHandler *next;
|
||||||
};
|
};
|
||||||
@ -180,6 +183,8 @@ struct RTPDemuxContext {
|
|||||||
unsigned int packet_count;
|
unsigned int packet_count;
|
||||||
unsigned int octet_count;
|
unsigned int octet_count;
|
||||||
unsigned int last_octet_count;
|
unsigned int last_octet_count;
|
||||||
|
int64_t last_feedback_time;
|
||||||
|
|
||||||
/* buffer for partially parsed packets */
|
/* buffer for partially parsed packets */
|
||||||
uint8_t buf[RTP_MAX_PACKET_LENGTH];
|
uint8_t buf[RTP_MAX_PACKET_LENGTH];
|
||||||
|
|
||||||
|
@ -380,6 +380,8 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
|
|||||||
get_word(buf1, sizeof(buf1), &p); /* protocol */
|
get_word(buf1, sizeof(buf1), &p); /* protocol */
|
||||||
if (!strcmp(buf1, "udp"))
|
if (!strcmp(buf1, "udp"))
|
||||||
rt->transport = RTSP_TRANSPORT_RAW;
|
rt->transport = RTSP_TRANSPORT_RAW;
|
||||||
|
else if (strstr(buf1, "/AVPF") || strstr(buf1, "/SAVPF"))
|
||||||
|
rtsp_st->feedback = 1;
|
||||||
|
|
||||||
/* XXX: handle list of formats */
|
/* XXX: handle list of formats */
|
||||||
get_word(buf1, sizeof(buf1), &p); /* format list */
|
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);
|
ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len);
|
||||||
} else if (rt->transport == RTSP_TRANSPORT_RTP) {
|
} else if (rt->transport == RTSP_TRANSPORT_RTP) {
|
||||||
ret = ff_rtp_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len);
|
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) {
|
if (ret < 0) {
|
||||||
/* Either bad packet, or a RTCP packet. Check if the
|
/* Either bad packet, or a RTCP packet. Check if the
|
||||||
* first_rtcp_ntp_time field was initialized. */
|
* first_rtcp_ntp_time field was initialized. */
|
||||||
|
@ -437,6 +437,9 @@ typedef struct RTSPStream {
|
|||||||
/** private data associated with the dynamic protocol */
|
/** private data associated with the dynamic protocol */
|
||||||
PayloadContext *dynamic_protocol_context;
|
PayloadContext *dynamic_protocol_context;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
/** Enable sending RTCP feedback messages according to RFC 4585 */
|
||||||
|
int feedback;
|
||||||
} RTSPStream;
|
} RTSPStream;
|
||||||
|
|
||||||
void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf,
|
void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf,
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
#define LIBAVFORMAT_VERSION_MAJOR 54
|
#define LIBAVFORMAT_VERSION_MAJOR 54
|
||||||
#define LIBAVFORMAT_VERSION_MINOR 59
|
#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, \
|
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
||||||
LIBAVFORMAT_VERSION_MINOR, \
|
LIBAVFORMAT_VERSION_MINOR, \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user