]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/rtpenc.c
libavformat: Add a muxer wrapping mpegts encoding into RTP
[ffmpeg] / libavformat / rtpenc.c
index 36064ed610b95e01a02e6b87c5773065c8e8cbfb..bf82da09697b29a2a34a5b9074c1053696263325 100644 (file)
 
 #include "rtpenc.h"
 
-//#define DEBUG
-
 static const AVOption options[] = {
     FF_RTP_FLAG_OPTS(RTPMuxContext, flags),
     { "payload_type", "Specify RTP payload type", offsetof(RTPMuxContext, payload_type), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 127, AV_OPT_FLAG_ENCODING_PARAM },
     { "ssrc", "Stream identifier", offsetof(RTPMuxContext, ssrc), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+    { "cname", "CNAME to include in RTCP SR packets", offsetof(RTPMuxContext, cname), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
+    { "seq", "Starting sequence number", offsetof(RTPMuxContext, seq), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 65535, AV_OPT_FLAG_ENCODING_PARAM },
     { NULL },
 };
 
@@ -49,9 +49,11 @@ static const AVClass rtp_muxer_class = {
 static int is_supported(enum AVCodecID id)
 {
     switch(id) {
+    case AV_CODEC_ID_H261:
     case AV_CODEC_ID_H263:
     case AV_CODEC_ID_H263P:
     case AV_CODEC_ID_H264:
+    case AV_CODEC_ID_HEVC:
     case AV_CODEC_ID_MPEG1VIDEO:
     case AV_CODEC_ID_MPEG2VIDEO:
     case AV_CODEC_ID_MPEG4:
@@ -77,6 +79,7 @@ static int is_supported(enum AVCodecID id)
     case AV_CODEC_ID_ILBC:
     case AV_CODEC_ID_MJPEG:
     case AV_CODEC_ID_SPEEX:
+    case AV_CODEC_ID_OPUS:
         return 1;
     default:
         return 0;
@@ -86,7 +89,7 @@ static int is_supported(enum AVCodecID id)
 static int rtp_write_header(AVFormatContext *s1)
 {
     RTPMuxContext *s = s1->priv_data;
-    int n;
+    int n, ret = AVERROR(EINVAL);
     AVStream *st;
 
     if (s1->nb_streams != 1) {
@@ -100,8 +103,17 @@ static int rtp_write_header(AVFormatContext *s1)
         return -1;
     }
 
-    if (s->payload_type < 0)
-        s->payload_type = ff_rtp_get_payload_type(s1, st->codec);
+    if (s->payload_type < 0) {
+        /* Re-validate non-dynamic payload types */
+        if (st->id < RTP_PT_PRIVATE)
+            st->id = ff_rtp_get_payload_type(s1, st->codec, -1);
+
+        s->payload_type = st->id;
+    } else {
+        /* private option takes priority */
+        st->id = s->payload_type;
+    }
+
     s->base_timestamp = av_get_random_seed();
     s->timestamp = s->base_timestamp;
     s->cur_timestamp = 0;
@@ -113,6 +125,13 @@ static int rtp_write_header(AVFormatContext *s1)
         /* Round the NTP time to whole milliseconds. */
         s->first_rtcp_ntp_time = (s1->start_time_realtime / 1000) * 1000 +
                                  NTP_OFFSET_US;
+    // Pick a random sequence start number, but in the lower end of the
+    // available range, so that any wraparound doesn't happen immediately.
+    // (Immediate wraparound would be an issue for SRTP.)
+    if (s->seq < 0)
+        s->seq = av_get_random_seed() & 0x0fff;
+    else
+        s->seq &= 0xffff; // Use the given parameter, wrapped to the right interval
 
     if (s1->packet_size) {
         if (s1->pb->max_packet_size)
@@ -125,7 +144,7 @@ static int rtp_write_header(AVFormatContext *s1)
         return AVERROR(EIO);
     }
     s->buf = av_malloc(s1->packet_size);
-    if (s->buf == NULL) {
+    if (!s->buf) {
         return AVERROR(ENOMEM);
     }
     s->max_payload_size = s1->packet_size - 12;
@@ -148,7 +167,12 @@ static int rtp_write_header(AVFormatContext *s1)
         }
         if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
             /* FIXME: We should round down here... */
-            s->max_frames_per_packet = av_rescale_q(s1->max_delay, (AVRational){1, 1000000}, st->codec->time_base);
+            if (st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0) {
+                s->max_frames_per_packet = av_rescale_q(s1->max_delay,
+                                                        (AVRational){1, 1000000},
+                                                        av_inv_q(st->avg_frame_rate));
+            } else
+                s->max_frames_per_packet = 1;
         }
     }
 
@@ -168,12 +192,32 @@ static int rtp_write_header(AVFormatContext *s1)
         s->max_payload_size = n * TS_PACKET_SIZE;
         s->buf_ptr = s->buf;
         break;
+    case AV_CODEC_ID_H261:
+        if (s1->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
+            av_log(s, AV_LOG_ERROR,
+                   "Packetizing H261 is experimental and produces incorrect "
+                   "packetization for cases where GOBs don't fit into packets "
+                   "(even though most receivers may handle it just fine). "
+                   "Please set -f_strict experimental in order to enable it.\n");
+            ret = AVERROR_EXPERIMENTAL;
+            goto fail;
+        }
+        break;
     case AV_CODEC_ID_H264:
         /* check for H.264 MP4 syntax */
         if (st->codec->extradata_size > 4 && st->codec->extradata[0] == 1) {
             s->nal_length_size = (st->codec->extradata[4] & 0x03) + 1;
         }
         break;
+    case AV_CODEC_ID_HEVC:
+        /* Only check for the standardized hvcC version of extradata, keeping
+         * things simple and similar to the avcC/H264 case above, instead
+         * of trying to handle the pre-standardization versions (as in
+         * libavcodec/hevc.c). */
+        if (st->codec->extradata_size > 21 && st->codec->extradata[0] == 1) {
+            s->nal_length_size = (st->codec->extradata[21] & 0x03) + 1;
+        }
+        break;
     case AV_CODEC_ID_VORBIS:
     case AV_CODEC_ID_THEORA:
         if (!s->max_frames_per_packet) s->max_frames_per_packet = 15;
@@ -186,6 +230,16 @@ static int rtp_write_header(AVFormatContext *s1)
          * 8000, even if the sample rate is 16000. See RFC 3551. */
         avpriv_set_pts_info(st, 32, 1, 8000);
         break;
+    case AV_CODEC_ID_OPUS:
+        if (st->codec->channels > 2) {
+            av_log(s1, AV_LOG_ERROR, "Multistream opus not supported in RTP\n");
+            goto fail;
+        }
+        /* The opus RTP RFC says that all opus streams should use 48000 Hz
+         * as clock rate, since all opus sample rates can be expressed in
+         * this clock rate, and sample rate changes on the fly are supported. */
+        avpriv_set_pts_info(st, 32, 1, 48000);
+        break;
     case AV_CODEC_ID_ILBC:
         if (st->codec->block_align != 38 && st->codec->block_align != 50) {
             av_log(s1, AV_LOG_ERROR, "Incorrect iLBC block size specified\n");
@@ -213,8 +267,11 @@ static int rtp_write_header(AVFormatContext *s1)
             av_log(s1, AV_LOG_ERROR, "Only mono is supported\n");
             goto fail;
         }
+        s->num_frames = 0;
+        goto defaultcase;
     case AV_CODEC_ID_AAC:
         s->num_frames = 0;
+        goto defaultcase;
     default:
 defaultcase:
         if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
@@ -228,11 +285,11 @@ defaultcase:
 
 fail:
     av_freep(&s->buf);
-    return AVERROR(EINVAL);
+    return ret;
 }
 
 /* send an rtcp sender report packet */
-static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time)
+static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time, int bye)
 {
     RTPMuxContext *s = s1->priv_data;
     uint32_t rtp_ts;
@@ -242,15 +299,37 @@ static void rtcp_send_sr(AVFormatContext *s1, int64_t ntp_time)
     s->last_rtcp_ntp_time = ntp_time;
     rtp_ts = av_rescale_q(ntp_time - s->first_rtcp_ntp_time, (AVRational){1, 1000000},
                           s1->streams[0]->time_base) + s->base_timestamp;
-    avio_w8(s1->pb, (RTP_VERSION << 6));
+    avio_w8(s1->pb, RTP_VERSION << 6);
     avio_w8(s1->pb, RTCP_SR);
     avio_wb16(s1->pb, 6); /* length in words - 1 */
     avio_wb32(s1->pb, s->ssrc);
-    avio_wb32(s1->pb, ntp_time / 1000000);
-    avio_wb32(s1->pb, ((ntp_time % 1000000) << 32) / 1000000);
+    avio_wb64(s1->pb, NTP_TO_RTP_FORMAT(ntp_time));
     avio_wb32(s1->pb, rtp_ts);
     avio_wb32(s1->pb, s->packet_count);
     avio_wb32(s1->pb, s->octet_count);
+
+    if (s->cname) {
+        int len = FFMIN(strlen(s->cname), 255);
+        avio_w8(s1->pb, (RTP_VERSION << 6) + 1);
+        avio_w8(s1->pb, RTCP_SDES);
+        avio_wb16(s1->pb, (7 + len + 3) / 4); /* length in words - 1 */
+
+        avio_wb32(s1->pb, s->ssrc);
+        avio_w8(s1->pb, 0x01); /* CNAME */
+        avio_w8(s1->pb, len);
+        avio_write(s1->pb, s->cname, len);
+        avio_w8(s1->pb, 0); /* END */
+        for (len = (7 + len) % 4; len % 4; len++)
+            avio_w8(s1->pb, 0);
+    }
+
+    if (bye) {
+        avio_w8(s1->pb, (RTP_VERSION << 6) | 1);
+        avio_w8(s1->pb, RTCP_BYE);
+        avio_wb16(s1->pb, 1); /* length in words - 1 */
+        avio_wb32(s1->pb, s->ssrc);
+    }
+
     avio_flush(s1->pb);
 }
 
@@ -263,7 +342,7 @@ void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m)
     av_dlog(s1, "rtp_send_data size=%d\n", len);
 
     /* build the RTP header */
-    avio_w8(s1->pb, (RTP_VERSION << 6));
+    avio_w8(s1->pb, RTP_VERSION << 6);
     avio_w8(s1->pb, (s->payload_type & 0x7f) | ((m & 0x01) << 7));
     avio_wb16(s1->pb, s->seq);
     avio_wb32(s1->pb, s->timestamp);
@@ -272,7 +351,7 @@ void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m)
     avio_write(s1->pb, buf1, len);
     avio_flush(s1->pb);
 
-    s->seq++;
+    s->seq = (s->seq + 1) & 0xffff;
     s->octet_count += len;
     s->packet_count++;
 }
@@ -388,6 +467,7 @@ static void rtp_send_mpegts_raw(AVFormatContext *s1,
     RTPMuxContext *s = s1->priv_data;
     int len, out_len;
 
+    s->timestamp = s->cur_timestamp;
     while (size >= TS_PACKET_SIZE) {
         len = s->max_payload_size - (s->buf_ptr - s->buf);
         if (len > size)
@@ -449,7 +529,7 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt)
     if ((s->first_packet || ((rtcp_bytes >= RTCP_SR_SIZE) &&
                             (ff_ntp_time() - s->last_rtcp_ntp_time > 5000000))) &&
         !(s->flags & FF_RTP_FLAG_SKIP_RTCP)) {
-        rtcp_send_sr(s1, ff_ntp_time());
+        rtcp_send_sr(s1, ff_ntp_time(), 0);
         s->last_octet_count = s->octet_count;
         s->first_packet = 0;
     }
@@ -499,6 +579,9 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt)
     case AV_CODEC_ID_H264:
         ff_rtp_send_h264(s1, pkt->data, size);
         break;
+    case AV_CODEC_ID_H261:
+        ff_rtp_send_h261(s1, pkt->data, size);
+        break;
     case AV_CODEC_ID_H263:
         if (s->flags & FF_RTP_FLAG_RFC2190) {
             int mb_info_size = 0;
@@ -512,6 +595,9 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt)
     case AV_CODEC_ID_H263P:
         ff_rtp_send_h263(s1, pkt->data, size);
         break;
+    case AV_CODEC_ID_HEVC:
+        ff_rtp_send_hevc(s1, pkt->data, size);
+        break;
     case AV_CODEC_ID_VORBIS:
     case AV_CODEC_ID_THEORA:
         ff_rtp_send_xiph(s1, pkt->data, size);
@@ -525,6 +611,14 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt)
     case AV_CODEC_ID_MJPEG:
         ff_rtp_send_jpeg(s1, pkt->data, size);
         break;
+    case AV_CODEC_ID_OPUS:
+        if (size > s->max_payload_size) {
+            av_log(s1, AV_LOG_ERROR,
+                   "Packet size %d too large for max RTP payload size %d\n",
+                   size, s->max_payload_size);
+            return AVERROR(EINVAL);
+        }
+        /* Intentional fallthrough */
     default:
         /* better than nothing : send the codec raw data */
         rtp_send_raw(s1, pkt->data, size);
@@ -537,6 +631,10 @@ static int rtp_write_trailer(AVFormatContext *s1)
 {
     RTPMuxContext *s = s1->priv_data;
 
+    /* If the caller closes and recreates ->pb, this might actually
+     * be NULL here even if it was successfully allocated at the start. */
+    if (s1->pb && (s->flags & FF_RTP_FLAG_SEND_BYE))
+        rtcp_send_sr(s1, ff_ntp_time(), 1);
     av_freep(&s->buf);
 
     return 0;
@@ -552,4 +650,5 @@ AVOutputFormat ff_rtp_muxer = {
     .write_packet      = rtp_write_packet,
     .write_trailer     = rtp_write_trailer,
     .priv_class        = &rtp_muxer_class,
+    .flags             = AVFMT_TS_NONSTRICT,
 };