[FFmpeg-devel] [PATCH] Add nit flag support v.2
Signed-off-by: Ubaldo Porcheddu --- doc/muxers.texi | 7 +++- libavformat/mpegtsenc.c | 100 +--- 2 files changed, 101 insertions(+), 6 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index e1c6ad0829..e77055e7ef 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 @item mpegts_copyts @var{boolean} @@ -1897,8 +1899,11 @@ 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}. +@item nit_period @var{duration} +Maximum time in seconds between NIT tables. Default is @code{0.5}. + @item tables_version @var{integer} -Set PAT, PMT and SDT version (default @code{0}, valid values are from 0 to 31, inclusively). +Set PAT, PMT, SDT and NIT version (default @code{0}, valid values are from 0 to 31, inclusively). This option allows updating stream structure so that standard consumer may detect the change. To do so, reopen output @code{AVFormatContext} (in case of API usage) or restart @command{ffmpeg} instance, cyclically changing diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c index e3f9d9ad50..47c8e7337a 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_B0x08 #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 */ @@ -260,6 +268,10 @@ static void mpegts_write_pat(AVFormatContext *s) int i; q = data; +if (ts->flags & MPEGTS_FLAG_NIT) { +put16(, 0x); +put16(, 0x0010); +} for (i = 0; i < ts->nb_services; i++) { service = ts->services[i]; put16(, service->sid); @@ -796,6 +808,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_descriptor +put16(, 0xf000 | ts->provider_name[0]); +*q++ = 0x40; +putbuf(, ts->provider_name, ts->provider_name[0]+1); + +//transport_stream_loop_length +loop_len_ptr = q; +q += 2; +put16(, ts->transport_stream_id); +put16(, ts->original_network_id); + +//transport_descriptors_length +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]; +} + +//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); +} + /* 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 +1019,8 @@ static void select_pcr_streams(AVFormatContext *s) static int mpegts_init(AVFormatContext *s) { MpegTSWrite *ts = s->priv_data; +AVDictionaryEntry *provider; +const char *provider_
[FFmpeg-devel] [PATCH] Add nit flag support
Signed-off-by: Ubaldo Porcheddu --- 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 @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_B0x08 #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 +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]; +} + +//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); +} + /* 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 = provid
Re: [FFmpeg-devel] [PATCH] Add optional NIT table generation
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
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
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".
[FFmpeg-devel] [PATCH] Add optional NIT table generation
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_