From c75bc9c3d6dbacfafd6572c31d0861ffb54c20cc Mon Sep 17 00:00:00 2001
From: Randrianasulu Andrew <randrianasulu@google.com>
Date: Thu, 5 May 2022 18:05:45 +0300
Subject: [PATCH 3/4] avformat/mpegtsenc: write SIT instead of SDT for m2ts

---
 doc/muxers.texi         |  3 +-
 libavformat/mpegtsenc.c | 65 ++++++++++++++++++++++++++++++++++++++---
 2 files changed, 63 insertions(+), 5 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 1af603b..575841c 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1924,7 +1924,8 @@ is less than 100 ms is used for VBR streams.
 Maximum time in seconds between PAT/PMT tables. Default is @code{0.1}.
 
 @item sdt_period @var{duration}
-Maximum time in seconds between SDT tables. Default is @code{0.5}.
+Maximum time in seconds between SDT tables. Default is @code{0.5}. Regardless
+of this setting no SDT is written in m2ts mode.
 
 @item nit_period @var{duration}
 Maximum time in seconds between NIT tables. Default is @code{0.5}.
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index 30735fc..0af9bc0 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -29,6 +29,7 @@
 
 #include "libavcodec/ac3_parser_internal.h"
 #include "libavcodec/startcode.h"
+#include "libavcodec/put_bits.h"
 
 #include "avformat.h"
 #include "avio_internal.h"
@@ -78,6 +79,7 @@ typedef struct MpegTSWrite {
     const AVClass *av_class;
     MpegTSSection pat; /* MPEG-2 PAT table */
     MpegTSSection sdt; /* MPEG-2 SDT table context */
+    MpegTSSection sit; /* MPEG-2 SIT table context */
     MpegTSSection nit; /* MPEG-2 NIT table context */
     MpegTSService **services;
     AVPacket *pkt;
@@ -206,8 +208,9 @@ static int mpegts_write_section1(MpegTSSection *s, int tid, int id,
 {
     uint8_t section[1024], *q;
     unsigned int tot_len;
-    /* reserved_future_use field must be set to 1 for SDT and NIT */
-    unsigned int flags = (tid == SDT_TID || tid == NIT_TID) ? 0xf000 : 0xb000;
+    /* reserved_future_use field must be set to 1 for SDT, SIT and NIT */
+    unsigned int flags = (tid == SDT_TID || tid == NIT_TID || tid == SIT_TID) ? 0xf000 : 0xb000;
+
 
     tot_len = 3 + 5 + len + 4;
     /* check if not too big */
@@ -235,6 +238,7 @@ static int mpegts_write_section1(MpegTSSection *s, int tid, int id,
 
 /* we retransmit the SI info at this rate */
 #define SDT_RETRANS_TIME 500
+#define SIT_RETRANS_TIME 500
 #define PAT_RETRANS_TIME 100
 #define PCR_RETRANS_TIME 20
 #define NIT_RETRANS_TIME 500
@@ -275,6 +279,10 @@ static void mpegts_write_pat(AVFormatContext *s)
         put16(&q, 0x0000);
         put16(&q, NIT_PID);
     }
+    if (ts->m2ts_mode) {
+        put16(&q, 0);
+        put16(&q, 0xe000 | SIT_PID);
+    }
     for (i = 0; i < ts->nb_services; i++) {
         service = ts->services[i];
         put16(&q, service->sid);
@@ -832,6 +840,44 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
     return 0;
 }
 
+static void mpegts_write_sit(AVFormatContext *s)
+{
+    MpegTSWrite *ts = s->priv_data;
+    uint8_t data[SECTION_LENGTH];
+    PutBitContext bs;
+
+    init_put_bits(&bs, data, sizeof(data));
+
+    put_bits(&bs,  4, 0x0f);    // DVB_reserved_for_future_use
+
+    if (ts->m2ts_mode) {
+        put_bits(&bs, 12, 0x0a);      // transmission_info_loop_length
+        put_bits(&bs,  8, 0x63);      // descriptor_tag - partial_transport_stream_descriptor
+        put_bits(&bs,  8, 0x08);      // descriptor_length
+        put_bits(&bs,  2, 0x03);      // DVB_reserved_future_use
+        put_bits(&bs, 22, ts->mux_rate / 400); // peak_rate
+        put_bits(&bs,  2, 0x03);      // DVB_reserved_future_use
+        put_bits(&bs, 22, 0x3fffff);  // minimum_overall_smoothing_rate
+        put_bits(&bs,  2, 0x03);      // DVB_reserved_future_use
+        put_bits(&bs, 14, 0x3fff);    // maximum_overall_smoothing_buffer
+    } else {
+        put_bits(&bs, 12, 0);         // transmission_info_loop_length
+    }
+
+    for (int i = 0; i < ts->nb_services; i++) {
+        put_bits(&bs, 16, ts->services[i]->sid & 0xffff); // service_id (equivalent to program_number)
+        put_bits(&bs,  1, 1);          // DVB_reserved_future_use
+        put_bits(&bs,  3, 0);          // running_status
+        put_bits(&bs, 12, 0);          // service_loop_length
+    }
+
+    flush_put_bits(&bs);
+
+    mpegts_write_section1(&ts->sit, SIT_TID, 0xffff, ts->tables_version, 0, 0,
+                          data, put_bits_count(&bs) >> 3);
+}
+
+
 static void mpegts_write_sdt(AVFormatContext *s)
 {
     MpegTSWrite *ts = s->priv_data;
@@ -1115,6 +1161,8 @@ static int mpegts_init(AVFormatContext *s)
             }
             av_log(s, AV_LOG_INFO, "Muxrate is not set for m2ts mode, using %d bps\n", ts->mux_rate);
         }
+        // this is used for sit period in m2ts mode
+        ts->sdt_period_us = SIT_RETRANS_TIME * 1000LL;
     }
 
     if (s->max_delay < 0) /* Not set by the caller */
@@ -1149,6 +1197,12 @@ static int mpegts_init(AVFormatContext *s)
     ts->sdt.write_packet = section_write_packet;
     ts->sdt.opaque       = s;
 
+    ts->sit.pid          = SIT_PID;
+    ts->sit.cc           = 15;
+    ts->sit.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT;
+    ts->sit.write_packet = section_write_packet;
+    ts->sit.opaque       = s;
+
     ts->nit.pid          = NIT_PID;
     ts->nit.cc           = 15;
     ts->nit.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT;
@@ -1314,7 +1368,10 @@ static void retransmit_si_info(AVFormatContext *s, int force_pat, int force_sdt,
     ) {
         if (pcr != AV_NOPTS_VALUE)
             ts->last_sdt_ts = FFMAX(pcr, ts->last_sdt_ts);
-        mpegts_write_sdt(s);
+        if (!ts->m2ts_mode)
+            mpegts_write_sdt(s);
+        else
+            mpegts_write_sit(s);
     }
     if ((pcr != AV_NOPTS_VALUE && ts->last_pat_ts == AV_NOPTS_VALUE) ||
         (pcr != AV_NOPTS_VALUE && pcr - ts->last_pat_ts >= ts->pat_period) ||
@@ -2300,7 +2357,7 @@ static const AVOption options[] = {
     { "nit", "Enable NIT transmission",
       0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_NIT}, 0, INT_MAX, ENC, "mpegts_flags" },
     { "mpegts_copyts", "don't offset dts/pts", OFFSET(copyts), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, ENC },
-    { "tables_version", "set PAT, PMT, SDT and NIT version", OFFSET(tables_version), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 31, ENC },
+    { "tables_version", "set PAT, PMT, SDT, SIT and NIT version", OFFSET(tables_version), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 31, ENC },
     { "omit_video_pes_length", "Omit the PES packet length for video packets",
       OFFSET(omit_video_pes_length), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, ENC },
     { "pcr_period", "PCR retransmission time in milliseconds",
-- 
2.35.1

