X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Frtpdec.c;h=6b0da9e63695261b193b3e9ca98d46c8c9b568b0;hb=f0c7fa2c484e197dae05fbda70a15b5e2ce81e9a;hp=e75a34cb93330a7e38d2cc13535eca91282025f4;hpb=b8eb0827f053230dd919bc73e25381b47b4fe1a7;p=ffmpeg diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c index e75a34cb933..6b0da9e6369 100644 --- a/libavformat/rtpdec.c +++ b/libavformat/rtpdec.c @@ -24,57 +24,60 @@ #include "libavutil/intreadwrite.h" #include "libavutil/time.h" +#include "libavcodec/bytestream.h" + #include "avformat.h" #include "network.h" #include "srtp.h" #include "url.h" #include "rtpdec.h" #include "rtpdec_formats.h" +#include "internal.h" #define MIN_FEEDBACK_INTERVAL 200000 /* 200 ms in us */ -static RTPDynamicProtocolHandler l24_dynamic_handler = { +static const RTPDynamicProtocolHandler l24_dynamic_handler = { .enc_name = "L24", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_PCM_S24BE, }; -static RTPDynamicProtocolHandler gsm_dynamic_handler = { +static const RTPDynamicProtocolHandler gsm_dynamic_handler = { .enc_name = "GSM", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_GSM, }; -static RTPDynamicProtocolHandler realmedia_mp3_dynamic_handler = { +static const RTPDynamicProtocolHandler realmedia_mp3_dynamic_handler = { .enc_name = "X-MP3-draft-00", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_MP3ADU, }; -static RTPDynamicProtocolHandler speex_dynamic_handler = { +static const RTPDynamicProtocolHandler speex_dynamic_handler = { .enc_name = "speex", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_SPEEX, }; -static RTPDynamicProtocolHandler opus_dynamic_handler = { +static const RTPDynamicProtocolHandler opus_dynamic_handler = { .enc_name = "opus", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_OPUS, }; -static RTPDynamicProtocolHandler t140_dynamic_handler = { /* RFC 4103 */ +static const RTPDynamicProtocolHandler t140_dynamic_handler = { /* RFC 4103 */ .enc_name = "t140", .codec_type = AVMEDIA_TYPE_SUBTITLE, .codec_id = AV_CODEC_ID_TEXT, }; -extern RTPDynamicProtocolHandler ff_rdt_video_handler; -extern RTPDynamicProtocolHandler ff_rdt_audio_handler; -extern RTPDynamicProtocolHandler ff_rdt_live_video_handler; -extern RTPDynamicProtocolHandler ff_rdt_live_audio_handler; +extern const RTPDynamicProtocolHandler ff_rdt_video_handler; +extern const RTPDynamicProtocolHandler ff_rdt_audio_handler; +extern const RTPDynamicProtocolHandler ff_rdt_live_video_handler; +extern const RTPDynamicProtocolHandler ff_rdt_live_audio_handler; -static const RTPDynamicProtocolHandler *rtp_dynamic_protocol_handler_list[] = { +static const RTPDynamicProtocolHandler *const rtp_dynamic_protocol_handler_list[] = { /* rtp */ &ff_ac3_dynamic_handler, &ff_amr_nb_dynamic_handler, @@ -401,40 +404,26 @@ int ff_rtp_check_and_send_back_rr(RTPDemuxContext *s, URLContext *fd, void ff_rtp_send_punch_packets(URLContext *rtp_handle) { - AVIOContext *pb; - uint8_t *buf; - int len; + uint8_t buf[RTP_MIN_PACKET_LENGTH], *ptr = buf; /* Send a small RTP packet */ - if (avio_open_dyn_buf(&pb) < 0) - return; - avio_w8(pb, (RTP_VERSION << 6)); - avio_w8(pb, 0); /* Payload type */ - avio_wb16(pb, 0); /* Seq */ - avio_wb32(pb, 0); /* Timestamp */ - avio_wb32(pb, 0); /* SSRC */ + bytestream_put_byte(&ptr, (RTP_VERSION << 6)); + bytestream_put_byte(&ptr, 0); /* Payload type */ + bytestream_put_be16(&ptr, 0); /* Seq */ + bytestream_put_be32(&ptr, 0); /* Timestamp */ + bytestream_put_be32(&ptr, 0); /* SSRC */ - avio_flush(pb); - len = avio_close_dyn_buf(pb, &buf); - if ((len > 0) && buf) - ffurl_write(rtp_handle, buf, len); - av_free(buf); + ffurl_write(rtp_handle, buf, ptr - buf); /* Send a minimal RTCP RR */ - if (avio_open_dyn_buf(&pb) < 0) - return; - - avio_w8(pb, (RTP_VERSION << 6)); - avio_w8(pb, RTCP_RR); /* receiver report */ - avio_wb16(pb, 1); /* length in words - 1 */ - avio_wb32(pb, 0); /* our own SSRC */ + ptr = buf; + bytestream_put_byte(&ptr, (RTP_VERSION << 6)); + bytestream_put_byte(&ptr, RTCP_RR); /* receiver report */ + bytestream_put_be16(&ptr, 1); /* length in words - 1 */ + bytestream_put_be32(&ptr, 0); /* our own SSRC */ - avio_flush(pb); - len = avio_close_dyn_buf(pb, &buf); - if ((len > 0) && buf) - ffurl_write(rtp_handle, buf, len); - av_free(buf); + ffurl_write(rtp_handle, buf, ptr - buf); } static int find_missing_packets(RTPDemuxContext *s, uint16_t *first_missing, @@ -531,6 +520,43 @@ int ff_rtp_send_rtcp_feedback(RTPDemuxContext *s, URLContext *fd, return 0; } +static int opus_write_extradata(AVCodecParameters *codecpar) +{ + uint8_t *bs; + int ret; + + /* This function writes an extradata with a channel mapping family of 0. + * This mapping family only supports mono and stereo layouts. And RFC7587 + * specifies that the number of channels in the SDP must be 2. + */ + if (codecpar->channels > 2) { + return AVERROR_INVALIDDATA; + } + + ret = ff_alloc_extradata(codecpar, 19); + if (ret < 0) + return ret; + + bs = (uint8_t *)codecpar->extradata; + + /* Opus magic */ + bytestream_put_buffer(&bs, "OpusHead", 8); + /* Version */ + bytestream_put_byte (&bs, 0x1); + /* Channel count */ + bytestream_put_byte (&bs, codecpar->channels); + /* Pre skip */ + bytestream_put_le16 (&bs, 0); + /* Input sample rate */ + bytestream_put_le32 (&bs, 48000); + /* Output gain */ + bytestream_put_le16 (&bs, 0x0); + /* Mapping family */ + bytestream_put_byte (&bs, 0x0); + + return 0; +} + /** * open a new RTP parse context for stream 'st'. 'st' can be NULL for * MPEG-2 TS streams. @@ -539,6 +565,7 @@ RTPDemuxContext *ff_rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_type, int queue_size) { RTPDemuxContext *s; + int ret; s = av_mallocz(sizeof(RTPDemuxContext)); if (!s) @@ -562,6 +589,16 @@ RTPDemuxContext *ff_rtp_parse_open(AVFormatContext *s1, AVStream *st, if (st->codecpar->sample_rate == 8000) st->codecpar->sample_rate = 16000; break; + case AV_CODEC_ID_OPUS: + ret = opus_write_extradata(st->codecpar); + if (ret < 0) { + av_log(s1, AV_LOG_ERROR, + "Error creating opus extradata: %s\n", + av_err2str(ret)); + av_free(s); + return NULL; + } + break; default: break; } @@ -585,6 +622,24 @@ void ff_rtp_parse_set_crypto(RTPDemuxContext *s, const char *suite, s->srtp_enabled = 1; } +static int rtp_set_prft(RTPDemuxContext *s, AVPacket *pkt, uint32_t timestamp) { + int64_t rtcp_time, delta_timestamp, delta_time; + + AVProducerReferenceTime *prft = + (AVProducerReferenceTime *) av_packet_new_side_data( + pkt, AV_PKT_DATA_PRFT, sizeof(AVProducerReferenceTime)); + if (!prft) + return AVERROR(ENOMEM); + + rtcp_time = ff_parse_ntp_time(s->last_rtcp_ntp_time) - NTP_OFFSET_US; + delta_timestamp = (int64_t)timestamp - (int64_t)s->last_rtcp_timestamp; + delta_time = av_rescale_q(delta_timestamp, s->st->time_base, AV_TIME_BASE_Q); + + prft->wallclock = rtcp_time + delta_time; + prft->flags = 24; + return 0; +} + /** * This was the second switch in rtp_parse packet. * Normalizes time, if required, sets stream_index, etc. @@ -596,6 +651,12 @@ static void finalize_packet(RTPDemuxContext *s, AVPacket *pkt, uint32_t timestam if (timestamp == RTP_NOTS_VALUE) return; + if (s->last_rtcp_ntp_time != AV_NOPTS_VALUE) { + if (rtp_set_prft(s, pkt, timestamp) < 0) { + av_log(s->ic, AV_LOG_WARNING, "rtpdec: failed to set prft"); + } + } + if (s->last_rtcp_ntp_time != AV_NOPTS_VALUE && s->ic->nb_streams > 1) { int64_t addend; int delta_timestamp; @@ -927,7 +988,7 @@ int ff_parse_fmtp(AVFormatContext *s, int ff_rtp_finalize_packet(AVPacket *pkt, AVIOContext **dyn_buf, int stream_idx) { int ret; - av_init_packet(pkt); + av_packet_unref(pkt); pkt->size = avio_close_dyn_buf(*dyn_buf, &pkt->data); pkt->stream_index = stream_idx;