I re-typed/re-applied your patches against ffmpeg.git, so hopefully we will
test them again soon (in Cin-gg) .
patch 0001 probably not needed anymore?
single.diff mostly for easier testing in our buildsystem...
---------- Forwarded message ----------
From: *Андрей Рандрианасулу* <[email protected]>
Date: Thursday, May 5, 2022
Subject: mpegts patches update to ffmpeg git
To: randrianasulu <[email protected]>
from https://github.com/cus/ffmpeg/commits/mpegts2
--
Андрей Рандрианасулу
From b9dd2068d6528d09d857e143e447cf76fb22a8cb Mon Sep 17 00:00:00 2001
From: Randrianasulu Andrew <[email protected]>
Date: Thu, 5 May 2022 17:40:48 +0300
Subject: [PATCH 1/4] avformat/mpegtsenc: count packets instead of using
avio_tell
---
libavformat/mpegtsenc.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index ead2ca2..a90258f 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -119,6 +119,7 @@ typedef struct MpegTSWrite {
int64_t last_pat_ts;
int64_t last_sdt_ts;
int64_t last_nit_ts;
+ int64_t nb_packets;
uint8_t provider_name[256];
@@ -946,7 +947,7 @@ invalid:
static int64_t get_pcr(const MpegTSWrite *ts)
{
- return av_rescale(ts->total_size + 11, 8 * PCR_TIME_BASE, ts->mux_rate) +
+ return av_rescale(ts->nb_packets * TS_PACKET_SIZE + 11, 8 * PCR_TIME_BASE, ts->mux_rate) +
ts->first_pcr;
}
@@ -962,6 +963,7 @@ static void write_packet(AVFormatContext *s, const uint8_t *packet)
}
avio_write(s->pb, packet, TS_PACKET_SIZE);
ts->total_size += TS_PACKET_SIZE;
+ ts->nb_packets++;
}
static void section_write_packet(MpegTSSection *s, const uint8_t *packet)
--
2.35.1
From fda335147e8f6621b318d3bfbad1934d2e793e9e Mon Sep 17 00:00:00 2001
From: Randrianasulu Andrew <[email protected]>
Date: Thu, 5 May 2022 17:42:03 +0300
Subject: [PATCH 2/4] avformat/mpegtsenc: simulate a CBR stream for m2ts mode
---
libavformat/mpegtsenc.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index a90258f..30735fc 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -36,6 +36,8 @@
#include "mpegts.h"
#define PCR_TIME_BASE 27000000
+#define M2TS_DEFAULT_MUXRATE 54000000
+#define M2TS_DEFAULT_UHD_MUXRATE 128000000
/* write DVB SI sections */
@@ -1104,6 +1106,15 @@ static int mpegts_init(AVFormatContext *s)
av_log(s, AV_LOG_ERROR, "Only one program is allowed in m2ts mode!\n");
return AVERROR(EINVAL);
}
+ if (ts->mux_rate <= 1) {
+ ts->mux_rate = M2TS_DEFAULT_MUXRATE;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVCodecParameters *codecpar = s->streams[i]->codecpar;
+ if (codecpar->codec_type == AVMEDIA_TYPE_VIDEO && codecpar->height > 1080)
+ ts->mux_rate = M2TS_DEFAULT_UHD_MUXRATE;
+ }
+ av_log(s, AV_LOG_INFO, "Muxrate is not set for m2ts mode, using %d bps\n", ts->mux_rate);
+ }
}
if (s->max_delay < 0) /* Not set by the caller */
@@ -1340,11 +1351,17 @@ static int write_pcr_bits(uint8_t *buf, int64_t pcr)
}
/* Write a single null transport stream packet */
-static void mpegts_insert_null_packet(AVFormatContext *s)
+static void mpegts_insert_null_packet(AVFormatContext *s, int force)
{
+ MpegTSWrite *ts = s->priv_data;
uint8_t *q;
uint8_t buf[TS_PACKET_SIZE];
+ if (ts->m2ts_mode && !force) {
+ ts->nb_packets++;
+ return;
+ }
+
q = buf;
*q++ = 0x47;
*q++ = 0x00 | 0x1f;
@@ -1538,7 +1555,7 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
if (write_pcr)
mpegts_insert_pcr_only(s, st);
else
- mpegts_insert_null_packet(s);
+ mpegts_insert_null_packet(s, 0);
/* recalculate write_pcr and possibly retransmit si_info */
continue;
}
@@ -2164,7 +2181,7 @@ static void mpegts_write_flush(AVFormatContext *s)
if (ts->m2ts_mode) {
int packets = (avio_tell(s->pb) / (TS_PACKET_SIZE + 4)) % 32;
while (packets++ < 32)
- mpegts_insert_null_packet(s);
+ mpegts_insert_null_packet(s, 1);
}
}
--
2.35.1
From c75bc9c3d6dbacfafd6572c31d0861ffb54c20cc Mon Sep 17 00:00:00 2001
From: Randrianasulu Andrew <[email protected]>
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
From 9e6853ee8ef4dc779749bffa853f690074ade445 Mon Sep 17 00:00:00 2001
From: Randrianasulu Andrew <[email protected]>
Date: Thu, 5 May 2022 18:19:02 +0300
Subject: [PATCH 4/4] avformat/mpegtsenc: support generating standalone PCR PID
for m2ts
---
libavformat/mpegtsenc.c | 40 +++++++++++++++++++++++++++++-----------
1 file changed, 29 insertions(+), 11 deletions(-)
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index 0af9bc0..f4c9e1f 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -39,6 +39,7 @@
#define PCR_TIME_BASE 27000000
#define M2TS_DEFAULT_MUXRATE 54000000
#define M2TS_DEFAULT_UHD_MUXRATE 128000000
+#define M2TS_PCR_RETRANS_TIME 50
/* write DVB SI sections */
@@ -106,6 +107,8 @@ typedef struct MpegTSWrite {
int m2ts_audio_pid;
int m2ts_pgssub_pid;
int m2ts_textsub_pid;
+ int64_t m2ts_pcr_period;
+ int64_t m2ts_last_pcr;
int pcr_period_ms;
#define MPEGTS_FLAG_REEMIT_PAT_PMT 0x01
@@ -1044,7 +1047,7 @@ static MpegTSService *mpegts_add_service(AVFormatContext *s, int sid,
return NULL;
service->pmt.pid = ts->pmt_start_pid + ts->nb_services;
service->sid = sid;
- service->pcr_pid = 0x1fff;
+ service->pcr_pid = ts->m2ts_mode ? M2TS_PCR_PID : 0x1fff;
if (encode_str8(service->provider_name, provider_name) < 0 ||
encode_str8(service->name, service_name) < 0) {
av_log(s, AV_LOG_ERROR, "Too long service or provider name\n");
@@ -1324,7 +1327,11 @@ static int mpegts_init(AVFormatContext *s)
if (ts->copyts < 1)
ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, AV_TIME_BASE);
- select_pcr_streams(s);
+ ts->m2ts_pcr_period = av_rescale(ts->pcr_period_ms == -1 ? M2TS_PCR_RETRANS_TIME : ts->pcr_period_ms, PCR_TIME_BASE, 1000);
+ ts->m2ts_last_pcr = ts->first_pcr - ts->m2ts_pcr_period;
+
+ if (!ts->m2ts_mode)
+ select_pcr_streams(s);
ts->last_pat_ts = AV_NOPTS_VALUE;
ts->last_sdt_ts = AV_NOPTS_VALUE;
@@ -1429,24 +1436,23 @@ static void mpegts_insert_null_packet(AVFormatContext *s, int force)
}
/* Write a single transport stream packet with a PCR and no payload */
-static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st)
+static void mpegts_insert_pcr_only(AVFormatContext *s, int pid, int cc, int *discontinuity)
{
MpegTSWrite *ts = s->priv_data;
- MpegTSWriteStream *ts_st = st->priv_data;
uint8_t *q;
uint8_t buf[TS_PACKET_SIZE];
q = buf;
*q++ = 0x47;
- *q++ = ts_st->pid >> 8;
- *q++ = ts_st->pid;
- *q++ = 0x20 | ts_st->cc; /* Adaptation only */
+ *q++ = pid >> 8;
+ *q++ = pid;
+ *q++ = 0x20 | cc; /* Adaptation only */
/* Continuity Count field does not increment (see 13818-1 section 2.4.3.3) */
*q++ = TS_PACKET_SIZE - 5; /* Adaptation Field Length */
*q++ = 0x10; /* Adaptation flags: PCR present */
- if (ts_st->discontinuity) {
+ if (discontinuity && *discontinuity) {
q[-1] |= 0x80;
- ts_st->discontinuity = 0;
+ *discontinuity = 0;
}
/* PCR coded into 6 bytes */
@@ -1457,6 +1463,12 @@ static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st)
write_packet(s, buf);
}
+static void mpegts_insert_pcr_only_for_stream(AVFormatContext *s, AVStream *st)
+{
+ MpegTSWriteStream *ts_st = st->priv_data;
+ mpegts_insert_pcr_only(s, ts_st->pid, ts_st->cc, &ts_st->discontinuity);
+}
+
static void write_pts(uint8_t *q, int fourbits, int64_t pts)
{
int val;
@@ -1586,6 +1598,11 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
pcr = get_pcr(ts);
if (pcr >= ts->next_pcr) {
int64_t next_pcr = INT64_MAX;
+ if (ts->m2ts_mode) {
+ mpegts_insert_pcr_only(s, M2TS_PCR_PID, 0, NULL);
+ ts->m2ts_last_pcr = FFMAX(pcr - ts->m2ts_pcr_period, ts->m2ts_last_pcr + ts->m2ts_pcr_period);
+ next_pcr = FFMIN(next_pcr, ts->m2ts_last_pcr + ts->m2ts_pcr_period);
+ } else {
for (int i = 0; i < s->nb_streams; i++) {
/* Make the current stream the last, because for that we
* can insert the pcr into the payload later */
@@ -1596,7 +1613,7 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
if (pcr - ts_st2->last_pcr >= ts_st2->pcr_period) {
ts_st2->last_pcr = FFMAX(pcr - ts_st2->pcr_period, ts_st2->last_pcr + ts_st2->pcr_period);
if (st2 != st) {
- mpegts_insert_pcr_only(s, st2);
+ mpegts_insert_pcr_only_for_stream(s, st2);
pcr = get_pcr(ts);
} else {
write_pcr = 1;
@@ -1605,12 +1622,13 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
next_pcr = FFMIN(next_pcr, ts_st2->last_pcr + ts_st2->pcr_period);
}
}
+ }
ts->next_pcr = next_pcr;
}
if (dts != AV_NOPTS_VALUE && (dts - pcr / 300) > delay) {
/* pcr insert gets priority over null packet insert */
if (write_pcr)
- mpegts_insert_pcr_only(s, st);
+ mpegts_insert_pcr_only_for_stream(s, st);
else
mpegts_insert_null_packet(s, 0);
/* recalculate write_pcr and possibly retransmit si_info */
--
2.35.1
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 ead2ca2..f4c9e1f 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"
@@ -36,6 +37,9 @@
#include "mpegts.h"
#define PCR_TIME_BASE 27000000
+#define M2TS_DEFAULT_MUXRATE 54000000
+#define M2TS_DEFAULT_UHD_MUXRATE 128000000
+#define M2TS_PCR_RETRANS_TIME 50
/* write DVB SI sections */
@@ -76,6 +80,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;
@@ -102,6 +107,8 @@ typedef struct MpegTSWrite {
int m2ts_audio_pid;
int m2ts_pgssub_pid;
int m2ts_textsub_pid;
+ int64_t m2ts_pcr_period;
+ int64_t m2ts_last_pcr;
int pcr_period_ms;
#define MPEGTS_FLAG_REEMIT_PAT_PMT 0x01
@@ -119,6 +126,7 @@ typedef struct MpegTSWrite {
int64_t last_pat_ts;
int64_t last_sdt_ts;
int64_t last_nit_ts;
+ int64_t nb_packets;
uint8_t provider_name[256];
@@ -203,8 +211,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 */
@@ -232,6 +241,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
@@ -272,6 +282,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);
@@ -829,6 +843,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;
@@ -946,7 +998,7 @@ invalid:
static int64_t get_pcr(const MpegTSWrite *ts)
{
- return av_rescale(ts->total_size + 11, 8 * PCR_TIME_BASE, ts->mux_rate) +
+ return av_rescale(ts->nb_packets * TS_PACKET_SIZE + 11, 8 * PCR_TIME_BASE, ts->mux_rate) +
ts->first_pcr;
}
@@ -962,6 +1014,7 @@ static void write_packet(AVFormatContext *s, const uint8_t *packet)
}
avio_write(s->pb, packet, TS_PACKET_SIZE);
ts->total_size += TS_PACKET_SIZE;
+ ts->nb_packets++;
}
static void section_write_packet(MpegTSSection *s, const uint8_t *packet)
@@ -994,7 +1047,7 @@ static MpegTSService *mpegts_add_service(AVFormatContext *s, int sid,
return NULL;
service->pmt.pid = ts->pmt_start_pid + ts->nb_services;
service->sid = sid;
- service->pcr_pid = 0x1fff;
+ service->pcr_pid = ts->m2ts_mode ? M2TS_PCR_PID : 0x1fff;
if (encode_str8(service->provider_name, provider_name) < 0 ||
encode_str8(service->name, service_name) < 0) {
av_log(s, AV_LOG_ERROR, "Too long service or provider name\n");
@@ -1102,6 +1155,17 @@ static int mpegts_init(AVFormatContext *s)
av_log(s, AV_LOG_ERROR, "Only one program is allowed in m2ts mode!\n");
return AVERROR(EINVAL);
}
+ if (ts->mux_rate <= 1) {
+ ts->mux_rate = M2TS_DEFAULT_MUXRATE;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVCodecParameters *codecpar = s->streams[i]->codecpar;
+ if (codecpar->codec_type == AVMEDIA_TYPE_VIDEO && codecpar->height > 1080)
+ ts->mux_rate = M2TS_DEFAULT_UHD_MUXRATE;
+ }
+ 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 */
@@ -1136,6 +1200,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;
@@ -1257,7 +1327,11 @@ static int mpegts_init(AVFormatContext *s)
if (ts->copyts < 1)
ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, AV_TIME_BASE);
- select_pcr_streams(s);
+ ts->m2ts_pcr_period = av_rescale(ts->pcr_period_ms == -1 ? M2TS_PCR_RETRANS_TIME : ts->pcr_period_ms, PCR_TIME_BASE, 1000);
+ ts->m2ts_last_pcr = ts->first_pcr - ts->m2ts_pcr_period;
+
+ if (!ts->m2ts_mode)
+ select_pcr_streams(s);
ts->last_pat_ts = AV_NOPTS_VALUE;
ts->last_sdt_ts = AV_NOPTS_VALUE;
@@ -1301,7 +1375,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) ||
@@ -1338,11 +1415,17 @@ static int write_pcr_bits(uint8_t *buf, int64_t pcr)
}
/* Write a single null transport stream packet */
-static void mpegts_insert_null_packet(AVFormatContext *s)
+static void mpegts_insert_null_packet(AVFormatContext *s, int force)
{
+ MpegTSWrite *ts = s->priv_data;
uint8_t *q;
uint8_t buf[TS_PACKET_SIZE];
+ if (ts->m2ts_mode && !force) {
+ ts->nb_packets++;
+ return;
+ }
+
q = buf;
*q++ = 0x47;
*q++ = 0x00 | 0x1f;
@@ -1353,24 +1436,23 @@ static void mpegts_insert_null_packet(AVFormatContext *s)
}
/* Write a single transport stream packet with a PCR and no payload */
-static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st)
+static void mpegts_insert_pcr_only(AVFormatContext *s, int pid, int cc, int *discontinuity)
{
MpegTSWrite *ts = s->priv_data;
- MpegTSWriteStream *ts_st = st->priv_data;
uint8_t *q;
uint8_t buf[TS_PACKET_SIZE];
q = buf;
*q++ = 0x47;
- *q++ = ts_st->pid >> 8;
- *q++ = ts_st->pid;
- *q++ = 0x20 | ts_st->cc; /* Adaptation only */
+ *q++ = pid >> 8;
+ *q++ = pid;
+ *q++ = 0x20 | cc; /* Adaptation only */
/* Continuity Count field does not increment (see 13818-1 section 2.4.3.3) */
*q++ = TS_PACKET_SIZE - 5; /* Adaptation Field Length */
*q++ = 0x10; /* Adaptation flags: PCR present */
- if (ts_st->discontinuity) {
+ if (discontinuity && *discontinuity) {
q[-1] |= 0x80;
- ts_st->discontinuity = 0;
+ *discontinuity = 0;
}
/* PCR coded into 6 bytes */
@@ -1381,6 +1463,12 @@ static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st)
write_packet(s, buf);
}
+static void mpegts_insert_pcr_only_for_stream(AVFormatContext *s, AVStream *st)
+{
+ MpegTSWriteStream *ts_st = st->priv_data;
+ mpegts_insert_pcr_only(s, ts_st->pid, ts_st->cc, &ts_st->discontinuity);
+}
+
static void write_pts(uint8_t *q, int fourbits, int64_t pts)
{
int val;
@@ -1510,6 +1598,11 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
pcr = get_pcr(ts);
if (pcr >= ts->next_pcr) {
int64_t next_pcr = INT64_MAX;
+ if (ts->m2ts_mode) {
+ mpegts_insert_pcr_only(s, M2TS_PCR_PID, 0, NULL);
+ ts->m2ts_last_pcr = FFMAX(pcr - ts->m2ts_pcr_period, ts->m2ts_last_pcr + ts->m2ts_pcr_period);
+ next_pcr = FFMIN(next_pcr, ts->m2ts_last_pcr + ts->m2ts_pcr_period);
+ } else {
for (int i = 0; i < s->nb_streams; i++) {
/* Make the current stream the last, because for that we
* can insert the pcr into the payload later */
@@ -1520,7 +1613,7 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
if (pcr - ts_st2->last_pcr >= ts_st2->pcr_period) {
ts_st2->last_pcr = FFMAX(pcr - ts_st2->pcr_period, ts_st2->last_pcr + ts_st2->pcr_period);
if (st2 != st) {
- mpegts_insert_pcr_only(s, st2);
+ mpegts_insert_pcr_only_for_stream(s, st2);
pcr = get_pcr(ts);
} else {
write_pcr = 1;
@@ -1529,14 +1622,15 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
next_pcr = FFMIN(next_pcr, ts_st2->last_pcr + ts_st2->pcr_period);
}
}
+ }
ts->next_pcr = next_pcr;
}
if (dts != AV_NOPTS_VALUE && (dts - pcr / 300) > delay) {
/* pcr insert gets priority over null packet insert */
if (write_pcr)
- mpegts_insert_pcr_only(s, st);
+ mpegts_insert_pcr_only_for_stream(s, st);
else
- mpegts_insert_null_packet(s);
+ mpegts_insert_null_packet(s, 0);
/* recalculate write_pcr and possibly retransmit si_info */
continue;
}
@@ -2162,7 +2256,7 @@ static void mpegts_write_flush(AVFormatContext *s)
if (ts->m2ts_mode) {
int packets = (avio_tell(s->pb) / (TS_PACKET_SIZE + 4)) % 32;
while (packets++ < 32)
- mpegts_insert_null_packet(s);
+ mpegts_insert_null_packet(s, 1);
}
}
@@ -2281,7 +2375,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",
--
Cin mailing list
[email protected]
https://lists.cinelerra-gg.org/mailman/listinfo/cin