diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c index 3d5b200099f26..51cf0fde07a1d 100644 --- a/libavformat/rtpdec.c +++ b/libavformat/rtpdec.c @@ -24,12 +24,15 @@ #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 */ @@ -529,6 +532,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. @@ -537,6 +577,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) @@ -560,6 +601,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; }