On Mon, 17 May 2021, Ubaldo Porcheddu wrote:

Signed-off-by: Ubaldo Porcheddu <uba...@eja.it>
---
doc/muxers.texi         |  2 ++
libavformat/mpegtsenc.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 93 insertions(+), 5 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index e1c6ad0829..f774d972a6 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1876,6 +1876,8 @@ Reemit PAT and PMT at each video frame.
Conform to System B (DVB) instead of System A (ATSC).
@item initial_discontinuity
Mark the initial packet of each stream as discontinuity.
+@item nit
+Emit NIT table.
@end table


The new option nit_period is still missing from the docs, please add that as well.

@item mpegts_copyts @var{boolean}
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index e3f9d9ad50..68abccf9ca 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -76,10 +76,12 @@ typedef struct MpegTSWrite {
    const AVClass *av_class;
    MpegTSSection pat; /* MPEG-2 PAT table */
    MpegTSSection sdt; /* MPEG-2 SDT table context */
+    MpegTSSection nit; /* MPEG-2 NIT table context */
    MpegTSService **services;
    AVPacket *pkt;
    int64_t sdt_period; /* SDT period in PCR time base */
    int64_t pat_period; /* PAT/PMT period in PCR time base */
+    int64_t nit_period; /* NIT period in PCR time base */
    int nb_services;
    int64_t first_pcr;
    int first_dts_checked;
@@ -107,13 +109,18 @@ typedef struct MpegTSWrite {
#define MPEGTS_FLAG_PAT_PMT_AT_FRAMES           0x04
#define MPEGTS_FLAG_SYSTEM_B        0x08
#define MPEGTS_FLAG_DISCONT         0x10
+#define MPEGTS_FLAG_NIT             0x20
    int flags;
    int copyts;
    int tables_version;
    int64_t pat_period_us;
    int64_t sdt_period_us;
+    int64_t nit_period_us;
    int64_t last_pat_ts;
    int64_t last_sdt_ts;
+    int64_t last_nit_ts;
+
+    uint8_t provider_name[256];

    int omit_video_pes_length;
} MpegTSWrite;
@@ -227,6 +234,7 @@ static int mpegts_write_section1(MpegTSSection *s, int tid, 
int id,
#define SDT_RETRANS_TIME 500
#define PAT_RETRANS_TIME 100
#define PCR_RETRANS_TIME 20
+#define NIT_RETRANS_TIME 500

typedef struct MpegTSWriteStream {
    int pid; /* stream associated pid */
@@ -796,6 +804,47 @@ static void mpegts_write_sdt(AVFormatContext *s)
                          data, q - data);
}

+static void mpegts_write_nit(AVFormatContext *s)
+{
+    int i;
+    MpegTSWrite *ts = s->priv_data;
+    uint8_t data[SECTION_LENGTH], *q, *desc_len_ptr, *loop_len_ptr;
+    AVProgram *program;
+
+    q = data;
+
+    //network name

Use the exact descriptor and field names, e.g.:

// network_descriptors_length

+    put16(&q, 0xf000 | ts->provider_name[0]);

// network_name_descriptor

+    *q++ = 0x40;
+    putbuf(&q, ts->provider_name, ts->provider_name[0]+1);
+
+    //TS loop
+    loop_len_ptr = q;
+    q += 2;
+    put16(&q, ts->transport_stream_id);
+    put16(&q, ts->original_network_id);
+
+    //transport descriptor
+    desc_len_ptr = q;
+    q += 2;
+
+    //service list descriptor
+    *q++ = 0x41;
+    *q++ = 3 * ts->nb_services;
+    for(i = 0; i < ts->nb_services; i++) {
+        put16(&q, ts->services[i]->sid);
+        *q++ = ts->service_type;
+        program = s->programs[i];
+    }
+
+    //calculate lengths
+    put16(&desc_len_ptr, 0xf000 | q - (desc_len_ptr+2));
+    put16(&loop_len_ptr, 0xf000 | q - (loop_len_ptr+2));
+
+    mpegts_write_section1(&ts->nit, NIT_TID, ts->original_network_id, 
ts->tables_version, 0, 0,
+                          data, q - data);
+}

If NIT generation is enabled, then you should also include the NIT PID in PAT for program 0. Please add that.

+
/* This stores a string in buf with the correct encoding and also sets the
 * first byte as the length. !str is accepted for an empty string.
 * If the string is already encoded, invalid UTF-8 or has no multibyte sequence
@@ -966,6 +1015,8 @@ static void select_pcr_streams(AVFormatContext *s)
static int mpegts_init(AVFormatContext *s)
{
    MpegTSWrite *ts = s->priv_data;
+    AVDictionaryEntry *provider;
+    const char *provider_name;
    int i, j;
    int ret;

@@ -1022,6 +1073,12 @@ static int mpegts_init(AVFormatContext *s)
    ts->sdt.write_packet = section_write_packet;
    ts->sdt.opaque       = s;

+    ts->nit.pid          = NIT_PID;
+    ts->nit.cc           = 15;
+    ts->nit.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT;
+    ts->nit.write_packet = section_write_packet;
+    ts->nit.opaque       = s;
+
    ts->pkt = av_packet_alloc();
    if (!ts->pkt)
        return AVERROR(ENOMEM);
@@ -1143,23 +1200,36 @@ static int mpegts_init(AVFormatContext *s)

    ts->last_pat_ts = AV_NOPTS_VALUE;
    ts->last_sdt_ts = AV_NOPTS_VALUE;
+    ts->last_nit_ts = AV_NOPTS_VALUE;
    ts->pat_period = av_rescale(ts->pat_period_us, PCR_TIME_BASE, AV_TIME_BASE);
    ts->sdt_period = av_rescale(ts->sdt_period_us, PCR_TIME_BASE, AV_TIME_BASE);
+    ts->nit_period = av_rescale(ts->nit_period_us, PCR_TIME_BASE, 
AV_TIME_BASE);
+
+    /* assign provider name */
+    provider = av_dict_get(s->metadata, "service_provider", NULL, 0);
+    provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME;
+    if (encode_str8(ts->provider_name, provider_name) < 0) {
+        av_log(s, AV_LOG_ERROR, "Too long provider name\n");
+        return AVERROR(EINVAL);
+    }

    if (ts->mux_rate == 1)
        av_log(s, AV_LOG_VERBOSE, "muxrate VBR, ");
    else
        av_log(s, AV_LOG_VERBOSE, "muxrate %d, ", ts->mux_rate);
    av_log(s, AV_LOG_VERBOSE,
-           "sdt every %"PRId64" ms, pat/pmt every %"PRId64" ms\n",
+           "sdt every %"PRId64" ms, pat/pmt every %"PRId64" ms",
           av_rescale(ts->sdt_period, 1000, PCR_TIME_BASE),
           av_rescale(ts->pat_period, 1000, PCR_TIME_BASE));
+    if (ts->flags & MPEGTS_FLAG_NIT)
+        av_log(s, AV_LOG_VERBOSE, ", nit every %"PRId64" ms", 
av_rescale(ts->nit_period, 1000, PCR_TIME_BASE));
+    av_log(s, AV_LOG_VERBOSE, "\n");

    return 0;
}

-/* send SDT, PAT and PMT tables regularly */
-static void retransmit_si_info(AVFormatContext *s, int force_pat, int 
force_sdt, int64_t pcr)
+/* send SDT, NIT, PAT and PMT tables regularly */
+static void retransmit_si_info(AVFormatContext *s, int force_pat, int 
force_sdt, int force_nit, int64_t pcr)
{
    MpegTSWrite *ts = s->priv_data;
    int i;
@@ -1172,6 +1242,15 @@ static void retransmit_si_info(AVFormatContext *s, int 
force_pat, int force_sdt,
            ts->last_sdt_ts = FFMAX(pcr, ts->last_sdt_ts);
        mpegts_write_sdt(s);
    }
+    if ((pcr != AV_NOPTS_VALUE && ts->last_nit_ts == AV_NOPTS_VALUE) ||
+        (pcr != AV_NOPTS_VALUE && pcr - ts->last_nit_ts >= ts->nit_period) ||
+        force_nit
+    ) {
+        if (pcr != AV_NOPTS_VALUE)
+            ts->last_nit_ts = FFMAX(pcr, ts->last_nit_ts);
+        if (ts->flags & MPEGTS_FLAG_NIT)
+            mpegts_write_nit(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) ||
        force_pat) {
@@ -1337,6 +1416,7 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream 
*st,
    int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE);
    int force_pat = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && key && 
!ts_st->prev_payload_key;
    int force_sdt = 0;
+    int force_nit = 0;

    av_assert0(ts_st->payload != buf || st->codecpar->codec_type != 
AVMEDIA_TYPE_VIDEO);
    if (ts->flags & MPEGTS_FLAG_PAT_PMT_AT_FRAMES && st->codecpar->codec_type 
== AVMEDIA_TYPE_VIDEO) {
@@ -1346,6 +1426,7 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream 
*st,
    if (ts->flags & MPEGTS_FLAG_REEMIT_PAT_PMT) {
        force_pat = 1;
        force_sdt = 1;
+        force_nit = 1;
        ts->flags &= ~MPEGTS_FLAG_REEMIT_PAT_PMT;
    }

@@ -1357,9 +1438,10 @@ static void mpegts_write_pes(AVFormatContext *s, 
AVStream *st,
        else if (dts != AV_NOPTS_VALUE)
            pcr = (dts - delay) * 300;

-        retransmit_si_info(s, force_pat, force_sdt, pcr);
+        retransmit_si_info(s, force_pat, force_sdt, force_nit, pcr);
        force_pat = 0;
        force_sdt = 0;
+        force_nit = 0;

        write_pcr = 0;
        if (ts->mux_rate > 1) {
@@ -2133,7 +2215,7 @@ static const AVOption options[] = {
    { "initial_discontinuity", "Mark initial packets as discontinuous",
      0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_DISCONT }, 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 and SDT version", 
OFFSET(tables_version), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 31, ENC },
+    { "tables_version", "set PAT, PMT, SDT 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",
@@ -2142,6 +2224,10 @@ static const AVOption options[] = {
      OFFSET(pat_period_us), AV_OPT_TYPE_DURATION, { .i64 = PAT_RETRANS_TIME * 
1000LL }, 0, INT64_MAX, ENC },
    { "sdt_period", "SDT retransmission time limit in seconds",
      OFFSET(sdt_period_us), AV_OPT_TYPE_DURATION, { .i64 = SDT_RETRANS_TIME * 
1000LL }, 0, INT64_MAX, ENC },
+    { "nit_period", "NIT retransmission time limit in seconds",
+      OFFSET(nit_period_us), AV_OPT_TYPE_DURATION, { .i64 = NIT_RETRANS_TIME * 
1000LL }, 0, INT64_MAX, ENC },
+    { "nit", "Enable NIT transmission",
+      0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_NIT}, 0, INT_MAX, ENC, 
"mpegts_flags" },
    { NULL },
};


Thanks,
Marton
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to