Re: [FFmpeg-devel] [PATCH] Add optional NIT table generation

2021-05-16 Thread Marton Balint




On Fri, 14 May 2021, Dominguez Bonini, David wrote:


Hi,


Hi Marton,

Il 2021-05-12 19:18 Marton Balint ha scritto:

On Wed, 12 May 2021, Ubaldo Porcheddu wrote:


Hi Marton,


+}
+
+//private data
+desc_len += 6 + 2;
+*q++ = 0x5F;
+*q++ = 4;
+*q++ = 0x00;
+*q++ = 0x00;
+put16(, 40);


What are these?


I didn't find any official document about it but this seems to be the
way many national (FR,IT,UK) broadcasters are writing the virtual
channel private data header and the one recognized by many popular tv
on the market.


But this looks like a separate descriptor from the virtual channels
(logical_channel_descriptor).


I think it is better to remove it until it is more clear what it does,
or maybe we add an extra mpegts flag like "nit_lcn_extra" ?



The private data specifier descriptor is needed for the TV to correctly process 
the LCN descriptor. When it is needed, you have to include both or none.
Also, in the Scandinavian countries, that use the NORDIG spec, the LCN 
descriptor has a different format, though I think the European format may still 
be understood.

Specs can be found here for NORDIG : 
https://nordig.org/wp-content/uploads/2017/03/NorDig-Unified_ver_2_6.pdf

Specs for the European LCN can be found here, it's the French spec, but the 
rest are the same: 
https://www.csa.fr/web/index.php/content/download/253685/723620/version/1/file/CSA-Signalling-Profilev3.4.pdf

Specs for the Australian LCN descriptor can be found here: 
https://www.freetv.com.au/wp-content/uploads/2019/08/OP-41-LCN-Descriptor-Issue-8-July-2016.pdf

The rules, as far as I know them are:

NORDIG --> Private Data Specifier = 0x0029,  LCN Descriptor Tag = 0x83 
(legacy), 0x87 (Nordig version)
United Kingdom --> Private Data Specifier = 0x233A,  LCN Descriptor Tag = 
0x83
Rest of Europe + Most of the World --> Private Data Specifier = 0x0028,  
LCN Descriptor Tag = 0x83
Australia --> _Do_not_include_Private_data_specifier_descriptor_ , LCN 
Descriptor Tag = 0x83

My suggestion would be to add an "LCN_mode" parameters, with values: NO_LCN, 
Australia,UK,Nordig, etc


Thanks for this, I agree with your suggestion.

It probably also makes sense to split the feature in two patches:

patch 1 adds support the nit flag (I think it is shorter than emit_nit) 
without LCN.


patch 2 add support for various lcn modes:
-lcn_mode (none|nordig|nordig_legacy|uk|australia|world).
And this would enable lcn generation in the NIT.

Regards,
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".


Re: [FFmpeg-devel] [PATCH] Add optional NIT table generation

2021-05-14 Thread Ubaldo Porcheddu

Hola David,

thank you for clarifying it, maybe we leave 0x28 by default and add a 
"nit_private" option for: none, NorDig, UK ?


Here is the function so far:

+static void mpegts_write_nit(AVFormatContext *s)
+{
+int i, lcn_count=0;
+MpegTSWrite *ts = s->priv_data;
+uint8_t data[SECTION_LENGTH], *q, *desc_len_ptr, *loop_len_ptr, 
*lcn_len_ptr;

+AVDictionaryEntry *logical_channel;
+AVProgram *program;
+
+q = data;
+
+//network name
+put16(, 0xf000 | ts->provider_name[0]);
+*q++ = 0x40;
+putbuf(, ts->provider_name, ts->provider_name[0]+1);
+
+//TS loop
+loop_len_ptr = q;
+q += 2;
+put16(, ts->transport_stream_id);
+put16(, 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(, ts->services[i]->sid);
+*q++ = ts->service_type;
+program = s->programs[i];
+if (av_dict_get(program->metadata, "logical_channel_number", 
NULL, 0))

+lcn_count++;
+}
+
+if (lcn_count > 0) {
+//logical channel descriptor
+*q++ = 0x83;
+lcn_len_ptr = q++;
+for (i = 0; i < ts->nb_services; i++) {
+program = s->programs[i];
+logical_channel = av_dict_get(program->metadata, 
"logical_channel_number", NULL, 0);

+if (logical_channel) {
+put16(, ts->services[i]->sid);
+put16(, 0xfc00 | atoi(logical_channel->value));
+}
+}
+*lcn_len_ptr = lcn_count * 4;
+//private data specifier descriptor
+*q++ = 0x5F;
+*q++ = 0x04;
+put16(, 0x00);
+put16(, 0x28);
+}
+
+//calculate lengths
+put16(_len_ptr, 0xf000 | q - (desc_len_ptr+2));
+put16(_len_ptr, 0xf000 | q - (loop_len_ptr+2));
+
+mpegts_write_section1(>nit, NIT_TID, ts->original_network_id, 
ts->tables_version, 0, 0,

+  data, q - data);
+}



Hi,


Hi Marton,

Il 2021-05-12 19:18 Marton Balint ha scritto:
> On Wed, 12 May 2021, Ubaldo Porcheddu wrote:
>
>> Hi Marton,
>>
 +}
 +
 +//private data
 +desc_len += 6 + 2;
 +*q++ = 0x5F;
 +*q++ = 4;
 +*q++ = 0x00;
 +*q++ = 0x00;
 +put16(, 40);
>>>
>>> What are these?
>>
>> I didn't find any official document about it but this seems to be the
>> way many national (FR,IT,UK) broadcasters are writing the virtual
>> channel private data header and the one recognized by many popular tv
>> on the market.
>
> But this looks like a separate descriptor from the virtual channels
> (logical_channel_descriptor).

I think it is better to remove it until it is more clear what it does,
or maybe we add an extra mpegts flag like "nit_lcn_extra" ?



The private data specifier descriptor is needed for the TV to
correctly process the LCN descriptor. When it is needed, you have to
include both or none.
Also, in the Scandinavian countries, that use the NORDIG spec, the LCN
descriptor has a different format, though I think the European format
may still be understood.

Specs can be found here for NORDIG :
https://nordig.org/wp-content/uploads/2017/03/NorDig-Unified_ver_2_6.pdf

Specs for the European LCN can be found here, it's the French spec,
but the rest are the same:
https://www.csa.fr/web/index.php/content/download/253685/723620/version/1/file/CSA-Signalling-Profilev3.4.pdf

Specs for the Australian LCN descriptor can be found here:
https://www.freetv.com.au/wp-content/uploads/2019/08/OP-41-LCN-Descriptor-Issue-8-July-2016.pdf

The rules, as far as I know them are:

NORDIG --> Private Data Specifier = 0x0029,  LCN Descriptor Tag =
0x83 (legacy), 0x87 (Nordig version)
United Kingdom --> Private Data Specifier = 0x233A,  LCN
Descriptor Tag = 0x83
Rest of Europe + Most of the World --> Private Data Specifier =
0x0028,  LCN Descriptor Tag = 0x83
Australia --> _Do_not_include_Private_data_specifier_descriptor_ , LCN
Descriptor Tag = 0x83

My suggestion would be to add an "LCN_mode" parameters, with values:
NO_LCN, Australia,UK,Nordig, etc

Regards

David


___
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".

___
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".


Re: [FFmpeg-devel] [PATCH] Add optional NIT table generation

2021-05-14 Thread Dominguez Bonini, David
Hi,

> Hi Marton,
> 
> Il 2021-05-12 19:18 Marton Balint ha scritto:
> > On Wed, 12 May 2021, Ubaldo Porcheddu wrote:
> >
> >> Hi Marton,
> >>
>  +}
>  +
>  +//private data
>  +desc_len += 6 + 2;
>  +*q++ = 0x5F;
>  +*q++ = 4;
>  +*q++ = 0x00;
>  +*q++ = 0x00;
>  +put16(, 40);
> >>>
> >>> What are these?
> >>
> >> I didn't find any official document about it but this seems to be the
> >> way many national (FR,IT,UK) broadcasters are writing the virtual
> >> channel private data header and the one recognized by many popular tv
> >> on the market.
> >
> > But this looks like a separate descriptor from the virtual channels
> > (logical_channel_descriptor).
> 
> I think it is better to remove it until it is more clear what it does,
> or maybe we add an extra mpegts flag like "nit_lcn_extra" ?
> 

The private data specifier descriptor is needed for the TV to correctly process 
the LCN descriptor. When it is needed, you have to include both or none. 
Also, in the Scandinavian countries, that use the NORDIG spec, the LCN 
descriptor has a different format, though I think the European format may still 
be understood.

Specs can be found here for NORDIG : 
https://nordig.org/wp-content/uploads/2017/03/NorDig-Unified_ver_2_6.pdf

Specs for the European LCN can be found here, it's the French spec, but the 
rest are the same: 
https://www.csa.fr/web/index.php/content/download/253685/723620/version/1/file/CSA-Signalling-Profilev3.4.pdf
 
Specs for the Australian LCN descriptor can be found here: 
https://www.freetv.com.au/wp-content/uploads/2019/08/OP-41-LCN-Descriptor-Issue-8-July-2016.pdf

The rules, as far as I know them are:

NORDIG --> Private Data Specifier = 0x0029,  LCN Descriptor Tag = 0x83 
(legacy), 0x87 (Nordig version)
United Kingdom --> Private Data Specifier = 0x233A,  LCN Descriptor Tag = 
0x83
Rest of Europe + Most of the World --> Private Data Specifier = 0x0028,  
LCN Descriptor Tag = 0x83
Australia --> _Do_not_include_Private_data_specifier_descriptor_ , LCN 
Descriptor Tag = 0x83

My suggestion would be to add an "LCN_mode" parameters, with values: NO_LCN, 
Australia,UK,Nordig, etc

Regards

David


___
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".


Re: [FFmpeg-devel] [PATCH] Add optional NIT table generation

2021-05-14 Thread Ubaldo Porcheddu

Hi Marton,

Il 2021-05-12 19:18 Marton Balint ha scritto:

On Wed, 12 May 2021, Ubaldo Porcheddu wrote:


Hi Marton,


+}
+
+//private data
+desc_len += 6 + 2;
+*q++ = 0x5F;
+*q++ = 4;
+*q++ = 0x00;
+*q++ = 0x00;
+put16(, 40);


What are these?


I didn't find any official document about it but this seems to be the 
way many national (FR,IT,UK) broadcasters are writing the virtual 
channel private data header and the one recognized by many popular tv 
on the market.


But this looks like a separate descriptor from the virtual channels
(logical_channel_descriptor).


I think it is better to remove it until it is more clear what it does, 
or maybe we add an extra mpegts flag like "nit_lcn_extra" ?



logical_channel_descriptor() is documented for example here:
https://forums.mediaspy.org/uploads/short-url/2wA2rGhOkh2yjlbcWMtcQizBv8L.pdf

So you should use the terminology that is used in the document above.


Ok, rewritten accordly.


+ts->nit_period = av_rescale(ts->nit_period_us, PCR_TIME_BASE,

AV_TIME_BASE);


if (ts->mux_rate == 1)
av_log(s, AV_LOG_VERBOSE, "muxrate VBR, ");
@@ -1154,12 +1237,14 @@ static int mpegts_init(AVFormatContext *s)
   "sdt every %"PRId64" ms, pat/pmt every %"PRId64" ms\n",
   av_rescale(ts->sdt_period, 1000, PCR_TIME_BASE),
   av_rescale(ts->pat_period, 1000, PCR_TIME_BASE));
+if (ts->nit_enable > 0)
+av_log(s, AV_LOG_VERBOSE, "nit every %"PRId64" ms\n",

av_rescale(ts->nit_period, 1000, PCR_TIME_BASE));

Maybe you should continue the last log line which already describes
the
interval of various tables, and not start a new line.


The idea is to have the NIT emission optional so I don't know if is a 
good idea to stat its periodical transmission on the same line, when 
disabled?


I meant something like:

av_log(s, AV_LOG_VERBOSE,
   "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 (nit_enabled)
 av_log(s, AV_LOG_VERBOSE, ", nit every %"PRId64" ms")
av_log(s, AV_LOG_VERBOSE, "\n")


Ok, clear now :)


Also docs/muxers.texi update is missing for the new feature.


is there any guide on what an how to add it? :)


No guide, but should be straightforward based on the existing
documentation of the mpegts muxer.


You mean something like this (I am changing "nit_enable" option with 
"nit_emit" flag):


--- ffmpeg.old/doc/muxers.texi  2021-05-09 18:20:04.0 +0200
+++ ffmpeg.new/doc/muxers.texi  2021-05-12 16:52:38.368198223 +0200
@@ -1876,6 +1876,8 @@
 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
+Emit NIT table.
 @end table

___
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".


Re: [FFmpeg-devel] [PATCH] Add optional NIT table generation

2021-05-12 Thread Marton Balint




On Wed, 12 May 2021, Ubaldo Porcheddu wrote:


Hi Marton,


+}
+
+//private data
+desc_len += 6 + 2;
+*q++ = 0x5F;
+*q++ = 4;
+*q++ = 0x00;
+*q++ = 0x00;
+put16(, 40);


What are these?


I didn't find any official document about it but this seems to be the way 
many national (FR,IT,UK) broadcasters are writing the virtual channel private 
data header and the one recognized by many popular tv on the market.


But this looks like a separate descriptor from the virtual channels 
(logical_channel_descriptor).


logical_channel_descriptor() is documented for example here:
https://forums.mediaspy.org/uploads/short-url/2wA2rGhOkh2yjlbcWMtcQizBv8L.pdf

So you should use the terminology that is used in the document above.




+ts->nit_period = av_rescale(ts->nit_period_us, PCR_TIME_BASE,

AV_TIME_BASE);


if (ts->mux_rate == 1)
av_log(s, AV_LOG_VERBOSE, "muxrate VBR, ");
@@ -1154,12 +1237,14 @@ static int mpegts_init(AVFormatContext *s)
   "sdt every %"PRId64" ms, pat/pmt every %"PRId64" ms\n",
   av_rescale(ts->sdt_period, 1000, PCR_TIME_BASE),
   av_rescale(ts->pat_period, 1000, PCR_TIME_BASE));
+if (ts->nit_enable > 0)
+av_log(s, AV_LOG_VERBOSE, "nit every %"PRId64" ms\n",

av_rescale(ts->nit_period, 1000, PCR_TIME_BASE));

Maybe you should continue the last log line which already describes
the
interval of various tables, and not start a new line.


The idea is to have the NIT emission optional so I don't know if is a good 
idea to stat its periodical transmission on the same line, when disabled?


I meant something like:

av_log(s, AV_LOG_VERBOSE,
   "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 (nit_enabled)
 av_log(s, AV_LOG_VERBOSE, ", nit every %"PRId64" ms")
av_log(s, AV_LOG_VERBOSE, "\n")




+{ "nit_enable", "Enable NIT transmission",
+  OFFSET(nit_enable), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC

},

As I wrote earlier, instead of a separate option, you should introduce
a
new flag in mpegts_flags.


ok almost ready also with this


Also docs/muxers.texi update is missing for the new feature.


is there any guide on what an how to add it? :)


No guide, but should be straightforward based on the existing 
documentation of the mpegts muxer.


Regards,
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".


Re: [FFmpeg-devel] [PATCH] Add optional NIT table generation

2021-05-12 Thread Ubaldo Porcheddu

Hi Marton,


+}
+
+//private data
+desc_len += 6 + 2;
+*q++ = 0x5F;
+*q++ = 4;
+*q++ = 0x00;
+*q++ = 0x00;
+put16(, 40);


What are these?


I didn't find any official document about it but this seems to be the 
way many national (FR,IT,UK) broadcasters are writing the virtual 
channel private data header and the one recognized by many popular tv on 
the market.



+ts->nit_period = av_rescale(ts->nit_period_us, PCR_TIME_BASE,

AV_TIME_BASE);


if (ts->mux_rate == 1)
av_log(s, AV_LOG_VERBOSE, "muxrate VBR, ");
@@ -1154,12 +1237,14 @@ static int mpegts_init(AVFormatContext *s)
   "sdt every %"PRId64" ms, pat/pmt every %"PRId64" ms\n",
   av_rescale(ts->sdt_period, 1000, PCR_TIME_BASE),
   av_rescale(ts->pat_period, 1000, PCR_TIME_BASE));
+if (ts->nit_enable > 0)
+av_log(s, AV_LOG_VERBOSE, "nit every %"PRId64" ms\n",

av_rescale(ts->nit_period, 1000, PCR_TIME_BASE));

Maybe you should continue the last log line which already describes
the
interval of various tables, and not start a new line.


The idea is to have the NIT emission optional so I don't know if is a 
good idea to stat its periodical transmission on the same line, when 
disabled?



+{ "nit_enable", "Enable NIT transmission",
+  OFFSET(nit_enable), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC

},

As I wrote earlier, instead of a separate option, you should introduce
a
new flag in mpegts_flags.


ok almost ready also with this


Also docs/muxers.texi update is missing for the new feature.


is there any guide on what an how to add it? :)

___
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".


Re: [FFmpeg-devel] [PATCH] Add optional NIT table generation

2021-05-02 Thread Marton Balint




On Tue, 27 Apr 2021, Ubaldo Porcheddu wrote:


Signed-off-by: Ubaldo Porcheddu 
---
libavformat/mpegtsenc.c | 110 ++--
1 file changed, 106 insertions(+), 4 deletions(-)

diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index a357f3a6aa..d03eaaa009 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;
@@ -112,10 +114,13 @@ typedef struct MpegTSWrite {
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;

int omit_video_pes_length;
+int nit_enable;


Instead of this, you should add a new MPEGTS_FLAG.


} MpegTSWrite;

/* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */
@@ -227,6 +232,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 +802,75 @@ static void mpegts_write_sdt(AVFormatContext *s)
  data, q - data);
}

+static void mpegts_write_nit(AVFormatContext *s)
+{
+int i, len=0, provider_len=0, desc_len=0, virtual_channel_value;
+MpegTSWrite *ts = s->priv_data;
+uint8_t data[SECTION_LENGTH], *q, *desc_len_ptr, *loop_len_ptr;
+AVDictionaryEntry *provider, *virtual_channel;
+AVProgram *program;
+const char *provider_name;
+
+q = data;
+
+//network name
+provider = av_dict_get(s->metadata, "service_provider", NULL, 0);
+provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME;
+provider_len = strlen(provider_name);
+put16(, 0xf000 | provider_len);
+*q++ = 0x40;
+*q++ = provider_len;
+putbuf(, provider_name, provider_len);


encode_str8 should be used instead. Better yet, you should pre-calculate 
that at init time, and used the already encoded value here directly.



+
+//TS loop
+loop_len_ptr = q;
+q += 2;
+put16(, ts->transport_stream_id);
+put16(, ts->original_network_id);
+
+//transport descriptor
+desc_len_ptr = q;
+q += 2;
+
+//service list
+len = 3 * ts->nb_services;
+desc_len += len;
+*q++ = 0x41; //tag
+*q++ = len;
+for(i = 0; i < ts->nb_services; i++) {
+  put16(, ts->services[i]->sid);//service_ID
+  *q++ = 0x01; //service type 0x01 for Digital TV Service


ts->service_type

Preferably you should use 4 space indentation.


+}
+
+//private data
+desc_len += 6 + 2;
+*q++ = 0x5F;
+*q++ = 4;
+*q++ = 0x00;
+*q++ = 0x00;
+put16(, 40);


What are these?


+
+//virtual channel
+len = 4 * ts->nb_services;
+desc_len += len + 2;
+*q++ = 0x83;
+*q++ = len;


Simply *q++ = 4 * ts->nb_services


+for (i = 0; i < ts->nb_services; i++) {
+  program = s->programs[i];
+  virtual_channel = av_dict_get(program->metadata, "virtual_channel", 
NULL, 0);
+  virtual_channel_value = virtual_channel ? atoi(virtual_channel->value) : 
1000+i;
+  put16(, ts->services[i]->sid);
+  put16(, 0xfc00 | virtual_channel_value);


indentation


+}
+
+//calculate lengths
+put16(_len_ptr, 0xf000 | desc_len);
+put16(_len_ptr, 0xf000 | desc_len+6);


You should not calculate desc_len, you should use
(q - desc_len_ptr) directly, it is less error-prone that way.


+
+mpegts_write_section1(>nit, NIT_TID, ts->original_network_id, 
ts->tables_version, 0, 0,
+  data, q - data);
+}
+
/* 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
@@ -1022,6 +1097,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,8 +1224,10 @@ static int mpegts_init(AVFormatContext *s)

ts->last_pat_ts = AV_NOPTS_VALUE;
ts->last_sdt_ts = AV_NOPTS_VALUE;
+ts->last_nit_ts = 

[FFmpeg-devel] [PATCH] Add optional NIT table generation

2021-04-27 Thread Ubaldo Porcheddu
Signed-off-by: Ubaldo Porcheddu 
---
 libavformat/mpegtsenc.c | 110 ++--
 1 file changed, 106 insertions(+), 4 deletions(-)

diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index a357f3a6aa..d03eaaa009 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;
@@ -112,10 +114,13 @@ typedef struct MpegTSWrite {
 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;
 
 int omit_video_pes_length;
+int nit_enable;
 } MpegTSWrite;
 
 /* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */
@@ -227,6 +232,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 +802,75 @@ static void mpegts_write_sdt(AVFormatContext *s)
   data, q - data);
 }
 
+static void mpegts_write_nit(AVFormatContext *s)
+{
+int i, len=0, provider_len=0, desc_len=0, virtual_channel_value;
+MpegTSWrite *ts = s->priv_data;
+uint8_t data[SECTION_LENGTH], *q, *desc_len_ptr, *loop_len_ptr;
+AVDictionaryEntry *provider, *virtual_channel;
+AVProgram *program;
+const char *provider_name;
+
+q = data;
+
+//network name
+provider = av_dict_get(s->metadata, "service_provider", NULL, 0);
+provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME;
+provider_len = strlen(provider_name);
+put16(, 0xf000 | provider_len);
+*q++ = 0x40;
+*q++ = provider_len;
+putbuf(, provider_name, provider_len);
+
+//TS loop
+loop_len_ptr = q;  
+q += 2;
+put16(, ts->transport_stream_id);
+put16(, ts->original_network_id);
+   
+//transport descriptor
+desc_len_ptr = q;  
+q += 2;
+
+//service list
+len = 3 * ts->nb_services;
+desc_len += len;
+*q++ = 0x41; //tag
+*q++ = len;
+for(i = 0; i < ts->nb_services; i++) {
+  put16(, ts->services[i]->sid);//service_ID
+  *q++ = 0x01; //service type 0x01 for Digital TV Service
+}
+   
+//private data
+desc_len += 6 + 2;
+*q++ = 0x5F;
+*q++ = 4;
+*q++ = 0x00;
+*q++ = 0x00;
+put16(, 40);
+
+//virtual channel
+len = 4 * ts->nb_services;
+desc_len += len + 2;
+*q++ = 0x83;
+*q++ = len;
+for (i = 0; i < ts->nb_services; i++) {
+  program = s->programs[i];
+  virtual_channel = av_dict_get(program->metadata, "virtual_channel", 
NULL, 0);
+  virtual_channel_value = virtual_channel ? atoi(virtual_channel->value) : 
1000+i;
+  put16(, ts->services[i]->sid); 
+  put16(, 0xfc00 | virtual_channel_value);
+}
+
+//calculate lengths
+put16(_len_ptr, 0xf000 | desc_len);
+put16(_len_ptr, 0xf000 | desc_len+6);
+
+mpegts_write_section1(>nit, NIT_TID, ts->original_network_id, 
ts->tables_version, 0, 0,
+  data, q - data);
+}
+
 /* 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
@@ -1022,6 +1097,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,8 +1224,10 @@ 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);
 
 if (ts->mux_rate == 1)
 av_log(s, AV_LOG_VERBOSE, "muxrate VBR, ");
@@ -1154,12 +1237,14 @@ static int mpegts_init(AVFormatContext *s)
"sdt