* commit '86d9181cf41edc3382bf2481f95a2fb321058689': rtpdec: Support sending RTCP feedback packets Conflicts: libavformat/version.h
Unified · Split
| @@ -30,6 +30,8 @@ · 29 unmodified lines | |||
| 30 | #include "rtpdec.h" | 30 | #include "rtpdec.h" |
| 31 | #include "rtpdec_formats.h" | 31 | #include "rtpdec_formats.h" |
| 32 | 32 | ||
| 33 | #define MIN_FEEDBACK_INTERVAL 200000 /* 200 ms in us */ | ||
| 34 | |||
| 33 | static RTPDynamicProtocolHandler realmedia_mp3_dynamic_handler = { | 35 | static RTPDynamicProtocolHandler realmedia_mp3_dynamic_handler = { |
| 34 | .enc_name = "X-MP3-draft-00", | 36 | .enc_name = "X-MP3-draft-00", |
| 35 | .codec_type = AVMEDIA_TYPE_AUDIO, | 37 | .codec_type = AVMEDIA_TYPE_AUDIO, |
| @@ -366,6 +368,100 @@ void ff_rtp_send_punch_packets(URLContext *rtp_handle) · 330 unmodified lines | |||
| 366 | av_free(buf); | 368 | av_free(buf); |
| 367 | } | 369 | } |
| 368 | 370 | ||
| 371 | static int find_missing_packets(RTPDemuxContext *s, uint16_t *first_missing, | ||
| 372 | uint16_t *missing_mask) | ||
| 373 | { | ||
| 374 | int i; | ||
| 375 | uint16_t next_seq = s->seq + 1; | ||
| 376 | RTPPacket *pkt = s->queue; | ||
| 377 | |||
| 378 | if (!pkt || pkt->seq == next_seq) | ||
| 379 | return 0; | ||
| 380 | |||
| 381 | *missing_mask = 0; | ||
| 382 | for (i = 1; i <= 16; i++) { | ||
| 383 | uint16_t missing_seq = next_seq + i; | ||
| 384 | while (pkt) { | ||
| 385 | int16_t diff = pkt->seq - missing_seq; | ||
| 386 | if (diff >= 0) | ||
| 387 | break; | ||
| 388 | pkt = pkt->next; | ||
| 389 | } | ||
| 390 | if (!pkt) | ||
| 391 | break; | ||
| 392 | if (pkt->seq == missing_seq) | ||
| 393 | continue; | ||
| 394 | *missing_mask |= 1 << (i - 1); | ||
| 395 | } | ||
| 396 | |||
| 397 | *first_missing = next_seq; | ||
| 398 | return 1; | ||
| 399 | } | ||
| 400 | |||
| 401 | int ff_rtp_send_rtcp_feedback(RTPDemuxContext *s, URLContext *fd, | ||
| 402 | AVIOContext *avio) | ||
| 403 | { | ||
| 404 | int len, need_keyframe, missing_packets; | ||
| 405 | AVIOContext *pb; | ||
| 406 | uint8_t *buf; | ||
| 407 | int64_t now; | ||
| 408 | uint16_t first_missing, missing_mask; | ||
| 409 | |||
| 410 | if (!fd && !avio) | ||
| 411 | return -1; | ||
| 412 | |||
| 413 | need_keyframe = s->handler && s->handler->need_keyframe && | ||
| 414 | s->handler->need_keyframe(s->dynamic_protocol_context); | ||
| 415 | missing_packets = find_missing_packets(s, &first_missing, &missing_mask); | ||
| 416 | |||
| 417 | if (!need_keyframe && !missing_packets) | ||
| 418 | return 0; | ||
| 419 | |||
| 420 | /* Send new feedback if enough time has elapsed since the last | ||
| 421 | * feedback packet. */ | ||
| 422 | |||
| 423 | now = av_gettime(); | ||
| 424 | if (s->last_feedback_time && | ||
| 425 | (now - s->last_feedback_time) < MIN_FEEDBACK_INTERVAL) | ||
| 426 | return 0; | ||
| 427 | s->last_feedback_time = now; | ||
| 428 | |||
| 429 | if (!fd) | ||
| 430 | pb = avio; | ||
| 431 | else if (avio_open_dyn_buf(&pb) < 0) | ||
| 432 | return -1; | ||
| 433 | |||
| 434 | if (need_keyframe) { | ||
| 435 | avio_w8(pb, (RTP_VERSION << 6) | 1); /* PLI */ | ||
| 436 | avio_w8(pb, RTCP_PSFB); | ||
| 437 | avio_wb16(pb, 2); /* length in words - 1 */ | ||
| 438 | // our own SSRC: we use the server's SSRC + 1 to avoid conflicts | ||
| 439 | avio_wb32(pb, s->ssrc + 1); | ||
| 440 | avio_wb32(pb, s->ssrc); // server SSRC | ||
| 441 | } | ||
| 442 | |||
| 443 | if (missing_packets) { | ||
| 444 | avio_w8(pb, (RTP_VERSION << 6) | 1); /* NACK */ | ||
| 445 | avio_w8(pb, RTCP_RTPFB); | ||
| 446 | avio_wb16(pb, 3); /* length in words - 1 */ | ||
| 447 | avio_wb32(pb, s->ssrc + 1); | ||
| 448 | avio_wb32(pb, s->ssrc); // server SSRC | ||
| 449 | |||
| 450 | avio_wb16(pb, first_missing); | ||
| 451 | avio_wb16(pb, missing_mask); | ||
| 452 | } | ||
| 453 | |||
| 454 | avio_flush(pb); | ||
| 455 | if (!fd) | ||
| 456 | return 0; | ||
| 457 | len = avio_close_dyn_buf(pb, &buf); | ||
| 458 | if (len > 0 && buf) { | ||
| 459 | ffurl_write(fd, buf, len); | ||
| 460 | av_free(buf); | ||
| 461 | } | ||
| 462 | return 0; | ||
| 463 | } | ||
| 464 | |||
| 369 | /** | 465 | /** |
| 370 | * open a new RTP parse context for stream 'st'. 'st' can be NULL for | 466 | * open a new RTP parse context for stream 'st'. 'st' can be NULL for |
| 371 | * MPEG2-TS streams to indicate that they should be demuxed inside the | 467 | * 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); · 72 unmodified lines | |||
| 73 | */ | 73 | */ |
| 74 | int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, URLContext *fd, | 74 | int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, URLContext *fd, |
| 75 | AVIOContext *avio, int count); | 75 | AVIOContext *avio, int count); |
| 76 | int ff_rtp_send_rtcp_feedback(RTPDemuxContext *s, URLContext *fd, | ||
| 77 | AVIOContext *avio); | ||
| 76 | 78 | ||
| 77 | // these statistics are used for rtcp receiver reports... | 79 | // these statistics are used for rtcp receiver reports... |
| 78 | typedef struct RTPStatistics { | 80 | typedef struct RTPStatistics { |
| @@ -130,6 +132,7 @@ struct RTPDynamicProtocolHandler { · 51 unmodified lines | |||
| 130 | void (*free)(PayloadContext *protocol_data); | 132 | void (*free)(PayloadContext *protocol_data); |
| 131 | /** Parse handler for this dynamic packet */ | 133 | /** Parse handler for this dynamic packet */ |
| 132 | DynamicPayloadPacketHandlerProc parse_packet; | 134 | DynamicPayloadPacketHandlerProc parse_packet; |
| 135 | int (*need_keyframe)(PayloadContext *context); | ||
| 133 | 136 | ||
| 134 | struct RTPDynamicProtocolHandler *next; | 137 | struct RTPDynamicProtocolHandler *next; |
| 135 | }; | 138 | }; |
| @@ -180,6 +183,8 @@ struct RTPDemuxContext { · 44 unmodified lines | |||
| 180 | unsigned int packet_count; | 183 | unsigned int packet_count; |
| 181 | unsigned int octet_count; | 184 | unsigned int octet_count; |
| 182 | unsigned int last_octet_count; | 185 | unsigned int last_octet_count; |
| 186 | int64_t last_feedback_time; | ||
| 187 | |||
| 183 | /* buffer for partially parsed packets */ | 188 | /* buffer for partially parsed packets */ |
| 184 | uint8_t buf[RTP_MAX_PACKET_LENGTH]; | 189 | uint8_t buf[RTP_MAX_PACKET_LENGTH]; |
| 185 | 190 | ||
| @@ -380,6 +380,8 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, · 379 unmodified lines | |||
| 380 | get_word(buf1, sizeof(buf1), &p); /* protocol */ | 380 | get_word(buf1, sizeof(buf1), &p); /* protocol */ |
| 381 | if (!strcmp(buf1, "udp")) | 381 | if (!strcmp(buf1, "udp")) |
| 382 | rt->transport = RTSP_TRANSPORT_RAW; | 382 | rt->transport = RTSP_TRANSPORT_RAW; |
| 383 | else if (strstr(buf1, "/AVPF") || strstr(buf1, "/SAVPF")) | ||
| 384 | rtsp_st->feedback = 1; | ||
| 383 | 385 | ||
| 384 | /* XXX: handle list of formats */ | 386 | /* XXX: handle list of formats */ |
| 385 | get_word(buf1, sizeof(buf1), &p); /* format list */ | 387 | get_word(buf1, sizeof(buf1), &p); /* format list */ |
| @@ -1932,6 +1934,12 @@ redo: · 1546 unmodified lines | |||
| 1932 | ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len); | 1934 | ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len); |
| 1933 | } else if (rt->transport == RTSP_TRANSPORT_RTP) { | 1935 | } else if (rt->transport == RTSP_TRANSPORT_RTP) { |
| 1934 | ret = ff_rtp_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len); | 1936 | ret = ff_rtp_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len); |
| 1937 | if (rtsp_st->feedback) { | ||
| 1938 | AVIOContext *pb = NULL; | ||
| 1939 | if (rt->lower_transport == RTSP_LOWER_TRANSPORT_CUSTOM) | ||
| 1940 | pb = s->pb; | ||
| 1941 | ff_rtp_send_rtcp_feedback(rtsp_st->transport_priv, rtsp_st->rtp_handle, pb); | ||
| 1942 | } | ||
| 1935 | if (ret < 0) { | 1943 | if (ret < 0) { |
| 1936 | /* Either bad packet, or a RTCP packet. Check if the | 1944 | /* Either bad packet, or a RTCP packet. Check if the |
| 1937 | * first_rtcp_ntp_time field was initialized. */ | 1945 | * first_rtcp_ntp_time field was initialized. */ |
| @@ -437,6 +437,9 @@ typedef struct RTSPStream { · 436 unmodified lines | |||
| 437 | /** private data associated with the dynamic protocol */ | 437 | /** private data associated with the dynamic protocol */ |
| 438 | PayloadContext *dynamic_protocol_context; | 438 | PayloadContext *dynamic_protocol_context; |
| 439 | //@} | 439 | //@} |
| 440 | |||
| 441 | /** Enable sending RTCP feedback messages according to RFC 4585 */ | ||
| 442 | int feedback; | ||
| 440 | } RTSPStream; | 443 | } RTSPStream; |
| 441 | 444 | ||
| 442 | void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf, | 445 | void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf, |
| @@ -31,7 +31,7 @@ · 30 unmodified lines | |||
| 31 | 31 | ||
| 32 | #define LIBAVFORMAT_VERSION_MAJOR 54 | 32 | #define LIBAVFORMAT_VERSION_MAJOR 54 |
| 33 | #define LIBAVFORMAT_VERSION_MINOR 59 | 33 | #define LIBAVFORMAT_VERSION_MINOR 59 |
| 34 | #define LIBAVFORMAT_VERSION_MICRO 106 | 34 | #define LIBAVFORMAT_VERSION_MICRO 107 |
| 35 | 35 | ||
| 36 | #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | 36 | #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ |
| 37 | LIBAVFORMAT_VERSION_MINOR, \ | 37 | LIBAVFORMAT_VERSION_MINOR, \ |