-diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
-index d827ba3e28..c8c6db979b 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
-@@ -56,7 +56,8 @@ typedef struct MpegTSService {
- int sid; /* service ID */
- uint8_t name[256];
- uint8_t provider_name[256];
-- int pcr_pid;
-+ int64_t pcr, pcr_packet_timer, pcr_packet_period;
-+ int pcr_sid, pcr_pid;
- AVProgram *program;
- } MpegTSService;
-
-@@ -76,11 +77,12 @@ typedef struct MpegTSWrite {
- MpegTSSection pat; /* MPEG-2 PAT table */
- MpegTSSection sdt; /* MPEG-2 SDT table context */
- MpegTSService **services;
-- int64_t sdt_period; /* SDT period in PCR time base */
-- int64_t pat_period; /* PAT/PMT period in PCR time base */
-+ int64_t sdt_packet_timer, sdt_packet_period;
-+ int64_t pat_packet_timer, pat_packet_period;
+@@ -84,9 +84,11 @@
+ 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;
- int64_t next_pcr;
-+ int onid;
-+ int tsid;
-+ int64_t pcr, first_pcr, delay;
++ int64_t pcr_pos, pcr;
++ int64_t first_pcr, next_pcr;
++ int64_t delay;
++ int pcr_stream_pid;
int mux_rate; ///< set to 1 when VBR
int pes_payload_size;
+ int64_t total_size;
+@@ -252,7 +254,7 @@
+ int data_st_warning;
-@@ -90,14 +92,14 @@ typedef struct MpegTSWrite {
- int service_type;
-
- int pmt_start_pid;
-+ int pcr_start_pid;
- int start_pid;
- int m2ts_mode;
-- int m2ts_video_pid;
-- int m2ts_audio_pid;
-- int m2ts_pgssub_pid;
-- int m2ts_textsub_pid;
-+ int64_t ts_offset;
-
-- int pcr_period_ms;
-+ int reemit_pat_pmt; // backward compatibility
-+
-+ double pcr_period;
- #define MPEGTS_FLAG_REEMIT_PAT_PMT 0x01
- #define MPEGTS_FLAG_AAC_LATM 0x02
- #define MPEGTS_FLAG_PAT_PMT_AT_FRAMES 0x04
-@@ -106,10 +108,8 @@ typedef struct MpegTSWrite {
- int flags;
- int copyts;
- int tables_version;
-- int64_t pat_period_us;
-- int64_t sdt_period_us;
-- int64_t last_pat_ts;
-- int64_t last_sdt_ts;
-+ double pat_period;
-+ double sdt_period;
-
- int omit_video_pes_length;
- } MpegTSWrite;
-@@ -217,14 +217,15 @@ static int mpegts_write_section1(MpegTSSection *s, int tid, int id,
- /* mpegts writer */
-
- #define DEFAULT_PROVIDER_NAME "FFmpeg"
--#define DEFAULT_SERVICE_NAME "Service"
-+#define DEFAULT_SERVICE_NAME "Service01"
-
--/* we retransmit the SI info at this rate */
-+/* we retransmit the SI info at this rate (ms) */
- #define SDT_RETRANS_TIME 500
- #define PAT_RETRANS_TIME 100
--#define PCR_RETRANS_TIME 20
-+#define PCR_RETRANS_TIME 50
-
- typedef struct MpegTSWriteStream {
-+ struct MpegTSService *service;
- int pid; /* stream associated pid */
- int cc;
- int discontinuity;
-@@ -236,10 +237,7 @@ typedef struct MpegTSWriteStream {
- int payload_flags;
- uint8_t *payload;
- AVFormatContext *amux;
-- int data_st_warning;
--
-- int64_t pcr_period; /* PCR period in PCR time base */
+ int64_t pcr_period; /* PCR period in PCR time base */
- int64_t last_pcr;
-+ AVRational user_tb;
++ int64_t pcr_timer;
/* For Opus */
int opus_queued_samples;
-@@ -259,7 +257,7 @@ static void mpegts_write_pat(AVFormatContext *s)
- put16(&q, service->sid);
- put16(&q, 0xe000 | service->pmt.pid);
- }
-- mpegts_write_section1(&ts->pat, PAT_TID, ts->transport_stream_id, ts->tables_version, 0, 0,
-+ mpegts_write_section1(&ts->pat, PAT_TID, ts->tsid, ts->tables_version, 0, 0,
- data, q - data);
- }
-
-@@ -281,148 +279,6 @@ static void put_registration_descriptor(uint8_t **q_ptr, uint32_t tag)
- *q_ptr = q;
- }
-
--static int get_dvb_stream_type(AVFormatContext *s, AVStream *st)
--{
-- MpegTSWrite *ts = s->priv_data;
-- MpegTSWriteStream *ts_st = st->priv_data;
-- int stream_type;
--
-- switch (st->codecpar->codec_id) {
-- case AV_CODEC_ID_MPEG1VIDEO:
-- case AV_CODEC_ID_MPEG2VIDEO:
-- stream_type = STREAM_TYPE_VIDEO_MPEG2;
-- break;
-- case AV_CODEC_ID_MPEG4:
-- stream_type = STREAM_TYPE_VIDEO_MPEG4;
-- break;
-- case AV_CODEC_ID_H264:
-- stream_type = STREAM_TYPE_VIDEO_H264;
-- break;
-- case AV_CODEC_ID_HEVC:
-- stream_type = STREAM_TYPE_VIDEO_HEVC;
-- break;
-- case AV_CODEC_ID_CAVS:
-- stream_type = STREAM_TYPE_VIDEO_CAVS;
-- break;
-- case AV_CODEC_ID_DIRAC:
-- stream_type = STREAM_TYPE_VIDEO_DIRAC;
-- break;
-- case AV_CODEC_ID_VC1:
-- stream_type = STREAM_TYPE_VIDEO_VC1;
-- break;
-- case AV_CODEC_ID_MP2:
-- case AV_CODEC_ID_MP3:
-- if ( st->codecpar->sample_rate > 0
-- && st->codecpar->sample_rate < 32000) {
-- stream_type = STREAM_TYPE_AUDIO_MPEG2;
-- } else {
-- stream_type = STREAM_TYPE_AUDIO_MPEG1;
-- }
-- break;
-- case AV_CODEC_ID_AAC:
-- stream_type = (ts->flags & MPEGTS_FLAG_AAC_LATM)
-- ? STREAM_TYPE_AUDIO_AAC_LATM
-- : STREAM_TYPE_AUDIO_AAC;
-- break;
-- case AV_CODEC_ID_AAC_LATM:
-- stream_type = STREAM_TYPE_AUDIO_AAC_LATM;
-- break;
-- case AV_CODEC_ID_AC3:
-- stream_type = (ts->flags & MPEGTS_FLAG_SYSTEM_B)
-- ? STREAM_TYPE_PRIVATE_DATA
-- : STREAM_TYPE_AUDIO_AC3;
-- break;
-- case AV_CODEC_ID_EAC3:
-- stream_type = (ts->flags & MPEGTS_FLAG_SYSTEM_B)
-- ? STREAM_TYPE_PRIVATE_DATA
-- : STREAM_TYPE_AUDIO_EAC3;
-- break;
-- case AV_CODEC_ID_DTS:
-- stream_type = STREAM_TYPE_AUDIO_DTS;
-- break;
-- case AV_CODEC_ID_TRUEHD:
-- stream_type = STREAM_TYPE_AUDIO_TRUEHD;
-- break;
-- case AV_CODEC_ID_OPUS:
-- stream_type = STREAM_TYPE_PRIVATE_DATA;
-- break;
-- case AV_CODEC_ID_TIMED_ID3:
-- stream_type = STREAM_TYPE_METADATA;
-- break;
-- case AV_CODEC_ID_DVB_SUBTITLE:
-- case AV_CODEC_ID_DVB_TELETEXT:
-- stream_type = STREAM_TYPE_PRIVATE_DATA;
-- break;
-- case AV_CODEC_ID_SMPTE_KLV:
-- if (st->codecpar->profile == FF_PROFILE_KLVA_SYNC) {
-- stream_type = STREAM_TYPE_METADATA;
-- } else {
-- stream_type = STREAM_TYPE_PRIVATE_DATA;
-- }
-- break;
-- default:
-- av_log_once(s, AV_LOG_WARNING, AV_LOG_DEBUG, &ts_st->data_st_warning,
-- "Stream %d, codec %s, is muxed as a private data stream "
-- "and may not be recognized upon reading.\n", st->index,
-- avcodec_get_name(st->codecpar->codec_id));
-- stream_type = STREAM_TYPE_PRIVATE_DATA;
-- break;
-- }
--
-- return stream_type;
--}
--
--static int get_m2ts_stream_type(AVFormatContext *s, AVStream *st)
--{
-- int stream_type;
-- MpegTSWriteStream *ts_st = st->priv_data;
--
-- switch (st->codecpar->codec_id) {
-- case AV_CODEC_ID_MPEG2VIDEO:
-- stream_type = STREAM_TYPE_VIDEO_MPEG2;
-- break;
-- case AV_CODEC_ID_H264:
-- stream_type = STREAM_TYPE_VIDEO_H264;
-- break;
-- case AV_CODEC_ID_VC1:
-- stream_type = STREAM_TYPE_VIDEO_VC1;
-- break;
-- case AV_CODEC_ID_HEVC:
-- stream_type = STREAM_TYPE_VIDEO_HEVC;
-- break;
-- case AV_CODEC_ID_PCM_BLURAY:
-- stream_type = 0x80;
-- break;
-- case AV_CODEC_ID_AC3:
-- stream_type = 0x81;
-- break;
-- case AV_CODEC_ID_DTS:
-- stream_type = (st->codecpar->channels > 6) ? 0x85 : 0x82;
-- break;
-- case AV_CODEC_ID_TRUEHD:
-- stream_type = 0x83;
-- break;
-- case AV_CODEC_ID_EAC3:
-- stream_type = 0x84;
-- break;
-- case AV_CODEC_ID_HDMV_PGS_SUBTITLE:
-- stream_type = 0x90;
-- break;
-- case AV_CODEC_ID_HDMV_TEXT_SUBTITLE:
-- stream_type = 0x92;
-- break;
-- default:
-- av_log_once(s, AV_LOG_WARNING, AV_LOG_DEBUG, &ts_st->data_st_warning,
-- "Stream %d, codec %s, is muxed as a private data stream "
-- "and may not be recognized upon reading.\n", st->index,
-- avcodec_get_name(st->codecpar->codec_id));
-- stream_type = STREAM_TYPE_PRIVATE_DATA;
-- break;
-- }
--
-- return stream_type;
--}
--
- static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
- {
- MpegTSWrite *ts = s->priv_data;
-@@ -436,14 +292,6 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
- q += 2; /* patched after */
-
- /* put program info here */
-- if (ts->m2ts_mode) {
-- put_registration_descriptor(&q, MKTAG('H', 'D', 'M', 'V'));
-- *q++ = 0x88; // descriptor_tag - hdmv_copy_control_descriptor
-- *q++ = 0x04; // descriptor_length
-- put16(&q, 0x0fff); // CA_System_ID
-- *q++ = 0xfc; // private_data_byte
-- *q++ = 0xfc; // private_data_byte
-- }
-
- val = 0xf000 | (q - program_info_length_ptr - 2);
- program_info_length_ptr[0] = val >> 8;
-@@ -472,8 +320,72 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
- err = 1;
- break;
- }
--
-- stream_type = ts->m2ts_mode ? get_m2ts_stream_type(s, st) : get_dvb_stream_type(s, st);
-+ switch (st->codecpar->codec_id) {
-+ case AV_CODEC_ID_MPEG1VIDEO:
-+ case AV_CODEC_ID_MPEG2VIDEO:
-+ stream_type = STREAM_TYPE_VIDEO_MPEG2;
-+ break;
-+ case AV_CODEC_ID_MPEG4:
-+ stream_type = STREAM_TYPE_VIDEO_MPEG4;
-+ break;
-+ case AV_CODEC_ID_H264:
-+ stream_type = STREAM_TYPE_VIDEO_H264;
-+ break;
-+ case AV_CODEC_ID_HEVC:
-+ stream_type = STREAM_TYPE_VIDEO_HEVC;
-+ break;
-+ case AV_CODEC_ID_CAVS:
-+ stream_type = STREAM_TYPE_VIDEO_CAVS;
-+ break;
-+ case AV_CODEC_ID_DIRAC:
-+ stream_type = STREAM_TYPE_VIDEO_DIRAC;
-+ break;
-+ case AV_CODEC_ID_VC1:
-+ stream_type = STREAM_TYPE_VIDEO_VC1;
-+ break;
-+ case AV_CODEC_ID_MP2:
-+ case AV_CODEC_ID_MP3:
-+ if ( st->codecpar->sample_rate > 0
-+ && st->codecpar->sample_rate < 32000) {
-+ stream_type = STREAM_TYPE_AUDIO_MPEG2;
-+ } else {
-+ stream_type = STREAM_TYPE_AUDIO_MPEG1;
-+ }
-+ break;
-+ case AV_CODEC_ID_AAC:
-+ stream_type = (ts->flags & MPEGTS_FLAG_AAC_LATM)
-+ ? STREAM_TYPE_AUDIO_AAC_LATM
-+ : STREAM_TYPE_AUDIO_AAC;
-+ break;
-+ case AV_CODEC_ID_AAC_LATM:
-+ stream_type = STREAM_TYPE_AUDIO_AAC_LATM;
-+ break;
-+ case AV_CODEC_ID_AC3:
-+ stream_type = (ts->flags & MPEGTS_FLAG_SYSTEM_B)
-+ ? STREAM_TYPE_PRIVATE_DATA
-+ : STREAM_TYPE_AUDIO_AC3;
-+ break;
-+ case AV_CODEC_ID_EAC3:
-+ stream_type = (ts->flags & MPEGTS_FLAG_SYSTEM_B)
-+ ? STREAM_TYPE_PRIVATE_DATA
-+ : STREAM_TYPE_AUDIO_EAC3;
-+ break;
-+ case AV_CODEC_ID_DTS:
-+ stream_type = STREAM_TYPE_AUDIO_DTS;
-+ break;
-+ case AV_CODEC_ID_TRUEHD:
-+ stream_type = STREAM_TYPE_AUDIO_TRUEHD;
-+ break;
-+ case AV_CODEC_ID_OPUS:
-+ stream_type = STREAM_TYPE_PRIVATE_DATA;
-+ break;
-+ case AV_CODEC_ID_TIMED_ID3:
-+ stream_type = STREAM_TYPE_METADATA;
-+ break;
-+ default:
-+ stream_type = STREAM_TYPE_PRIVATE_DATA;
-+ break;
-+ }
-
- *q++ = stream_type;
- put16(&q, 0xe000 | ts_st->pid);
-@@ -736,7 +648,7 @@ static void mpegts_write_sdt(AVFormatContext *s)
- int i, running_status, free_ca_mode, val;
-
- q = data;
-- put16(&q, ts->original_network_id);
-+ put16(&q, ts->onid);
- *q++ = 0xff;
- for (i = 0; i < ts->nb_services; i++) {
- service = ts->services[i];
-@@ -762,7 +674,7 @@ static void mpegts_write_sdt(AVFormatContext *s)
- desc_list_len_ptr[0] = val >> 8;
- desc_list_len_ptr[1] = val;
- }
-- mpegts_write_section1(&ts->sdt, SDT_TID, ts->transport_stream_id, ts->tables_version, 0, 0,
-+ mpegts_write_section1(&ts->sdt, SDT_TID, ts->tsid, ts->tables_version, 0, 0,
- data, q - data);
- }
-
-@@ -802,49 +714,12 @@ invalid:
+@@ -945,18 +947,18 @@
return 0;
}
--static int64_t get_pcr(const MpegTSWrite *ts, AVIOContext *pb)
--{
-- return av_rescale(avio_tell(pb) + 11, 8 * PCR_TIME_BASE, ts->mux_rate) +
-- ts->first_pcr;
--}
--
--static void write_packet(AVFormatContext *s, const uint8_t *packet)
--{
-- MpegTSWrite *ts = s->priv_data;
-- if (ts->m2ts_mode) {
-- int64_t pcr = get_pcr(s->priv_data, s->pb);
-- uint32_t tp_extra_header = pcr % 0x3fffffff;
-- tp_extra_header = AV_RB32(&tp_extra_header);
-- avio_write(s->pb, (unsigned char *) &tp_extra_header,
-- sizeof(tp_extra_header));
-- }
-- avio_write(s->pb, packet, TS_PACKET_SIZE);
--}
--
--static void section_write_packet(MpegTSSection *s, const uint8_t *packet)
--{
-- AVFormatContext *ctx = s->opaque;
-- write_packet(ctx, packet);
--}
--
- static MpegTSService *mpegts_add_service(AVFormatContext *s, int sid,
-- const AVDictionary *metadata,
-- AVProgram *program)
-+ const char *provider_name,
-+ const char *name)
+-static int64_t get_pcr(const MpegTSWrite *ts)
++static int64_t get_pcr(const MpegTSWrite *ts, AVIOContext *pb)
{
- MpegTSWrite *ts = s->priv_data;
- MpegTSService *service;
-- AVDictionaryEntry *title, *provider;
-- char default_service_name[32];
-- const char *service_name;
-- const char *provider_name;
--
-- title = av_dict_get(metadata, "service_name", NULL, 0);
-- if (!title)
-- title = av_dict_get(metadata, "title", NULL, 0);
-- snprintf(default_service_name, sizeof(default_service_name), "%s%02d", DEFAULT_SERVICE_NAME, ts->nb_services + 1);
-- service_name = title ? title->value : default_service_name;
-- provider = av_dict_get(metadata, "service_provider", NULL, 0);
-- provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME;
-
- service = av_mallocz(sizeof(MpegTSService));
- if (!service)
-@@ -852,92 +727,57 @@ static MpegTSService *mpegts_add_service(AVFormatContext *s, int sid,
- service->pmt.pid = ts->pmt_start_pid + ts->nb_services;
- service->sid = sid;
- service->pcr_pid = 0x1fff;
-+ service->pcr_sid = 0x1fff;
- if (encode_str8(service->provider_name, provider_name) < 0 ||
-- encode_str8(service->name, service_name) < 0) {
-+ encode_str8(service->name, name) < 0) {
- av_log(s, AV_LOG_ERROR, "Too long service or provider name\n");
- goto fail;
- }
- if (av_dynarray_add_nofree(&ts->services, &ts->nb_services, service) < 0)
- goto fail;
-
-- service->pmt.write_packet = section_write_packet;
-- service->pmt.opaque = s;
-- service->pmt.cc = 15;
-- service->pmt.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT;
-- service->program = program;
--
- return service;
- fail:
- av_free(service);
- return NULL;
+- return av_rescale(ts->total_size + 11, 8 * PCR_TIME_BASE, ts->mux_rate) +
+- ts->first_pcr;
++ int64_t pos = avio_tell(pb) + 11;
++ return ts->pcr + (ts->mux_rate == 1 ? (pos - ts->pcr_pos) * 8 :
++ av_rescale(pos - ts->pcr_pos, 8 * PCR_TIME_BASE, ts->mux_rate));
}
--static void enable_pcr_generation_for_stream(AVFormatContext *s, AVStream *pcr_st)
-+static void mpegts_prefix_m2ts_header(AVFormatContext *s)
+ static void write_packet(AVFormatContext *s, const uint8_t *packet)
{
MpegTSWrite *ts = s->priv_data;
-- MpegTSWriteStream *ts_st = pcr_st->priv_data;
--
-- if (ts->mux_rate > 1 || ts->pcr_period_ms >= 0) {
-- int pcr_period_ms = ts->pcr_period_ms == -1 ? PCR_RETRANS_TIME : ts->pcr_period_ms;
-- ts_st->pcr_period = av_rescale(pcr_period_ms, PCR_TIME_BASE, 1000);
-- } else {
-- /* By default, for VBR we select the highest multiple of frame duration which is less than 100 ms. */
-- int64_t frame_period = 0;
-- if (pcr_st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
-- int frame_size = av_get_audio_frame_duration2(pcr_st->codecpar, 0);
-- if (!frame_size) {
-- av_log(s, AV_LOG_WARNING, "frame size not set\n");
-- frame_size = 512;
-- }
-- frame_period = av_rescale_rnd(frame_size, PCR_TIME_BASE, pcr_st->codecpar->sample_rate, AV_ROUND_UP);
-- } else if (pcr_st->avg_frame_rate.num) {
-- frame_period = av_rescale_rnd(pcr_st->avg_frame_rate.den, PCR_TIME_BASE, pcr_st->avg_frame_rate.num, AV_ROUND_UP);
-- }
-- if (frame_period > 0 && frame_period <= PCR_TIME_BASE / 10)
-- ts_st->pcr_period = frame_period * (PCR_TIME_BASE / 10 / frame_period);
-- else
-- ts_st->pcr_period = 1;
-+ if (ts->m2ts_mode) {
-+ uint32_t tp_extra_header = ts->pcr % 0x3fffffff;
-+ tp_extra_header = AV_RB32(&tp_extra_header);
-+ avio_write(s->pb, (unsigned char *) &tp_extra_header,
-+ sizeof(tp_extra_header));
+ if (ts->m2ts_mode) {
+- int64_t pcr = get_pcr(s->priv_data);
+- uint32_t tp_extra_header = pcr % 0x3fffffff;
++ uint32_t tp_extra_header = get_pcr(ts, s->pb) % 0x3fffffff;
+ tp_extra_header = AV_RB32(&tp_extra_header);
+ avio_write(s->pb, (unsigned char *) &tp_extra_header,
+ sizeof(tp_extra_header));
+@@ -1042,9 +1044,6 @@
+ else
+ ts_st->pcr_period = 1;
}
-
- // output a PCR as soon as possible
- ts_st->last_pcr = ts->first_pcr - ts_st->pcr_period;
}
--static void select_pcr_streams(AVFormatContext *s)
-+static void section_write_packet(MpegTSSection *s, const uint8_t *packet)
- {
-- MpegTSWrite *ts = s->priv_data;
--
-- for (int i = 0; i < ts->nb_services; i++) {
-- MpegTSService *service = ts->services[i];
-- AVStream *pcr_st = NULL;
-- AVProgram *program = service->program;
-- int nb_streams = program ? program->nb_stream_indexes : s->nb_streams;
--
-- for (int j = 0; j < nb_streams; j++) {
-- AVStream *st = s->streams[program ? program->stream_index[j] : j];
-- if (!pcr_st ||
-- pcr_st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
-- {
-- pcr_st = st;
-- }
-- }
--
-- if (pcr_st) {
-- MpegTSWriteStream *ts_st = pcr_st->priv_data;
-- service->pcr_pid = ts_st->pid;
-- enable_pcr_generation_for_stream(s, pcr_st);
-- av_log(s, AV_LOG_VERBOSE, "service %i using PCR in pid=%i, pcr_period=%"PRId64"ms\n",
-- service->sid, service->pcr_pid, av_rescale(ts_st->pcr_period, 1000, PCR_TIME_BASE));
-- }
-- }
-+ AVFormatContext *ctx = s->opaque;
-+ mpegts_prefix_m2ts_header(ctx);
-+ avio_write(ctx->pb, packet, TS_PACKET_SIZE);
- }
-
- static int mpegts_init(AVFormatContext *s)
- {
- MpegTSWrite *ts = s->priv_data;
-+ MpegTSWriteStream *ts_st;
-+ MpegTSService *service;
-+ AVStream *st, *pcr_st = NULL;
-+ AVDictionaryEntry *title, *provider;
-+ double clk_rate;
- int i, j;
-+ const char *service_name;
-+ const char *provider_name;
-+ int *pids;
- int ret;
+ static void select_pcr_streams(AVFormatContext *s)
+@@ -1107,6 +1106,7 @@
-+ if (s->max_delay < 0) /* Not set by the caller */
-+ s->max_delay = 0;
+ if (s->max_delay < 0) /* Not set by the caller */
+ s->max_delay = 0;
+ ts->delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE);
-+
- if (ts->m2ts_mode == -1) {
- if (av_match_ext(s->url, "m2ts")) {
- ts->m2ts_mode = 1;
-@@ -946,36 +786,53 @@ static int mpegts_init(AVFormatContext *s)
- }
- }
-- ts->m2ts_video_pid = M2TS_VIDEO_PID;
-- ts->m2ts_audio_pid = M2TS_AUDIO_START_PID;
-- ts->m2ts_pgssub_pid = M2TS_PGSSUB_START_PID;
-- ts->m2ts_textsub_pid = M2TS_TEXTSUB_PID;
--
-- if (ts->m2ts_mode) {
-- ts->pmt_start_pid = M2TS_PMT_PID;
-- if (s->nb_programs > 1) {
-- av_log(s, AV_LOG_ERROR, "Only one program is allowed in m2ts mode!\n");
-- return AVERROR(EINVAL);
-- }
-- }
--
-- if (s->max_delay < 0) /* Not set by the caller */
-- s->max_delay = 0;
--
// round up to a whole number of TS packets
ts->pes_payload_size = (ts->pes_payload_size + 14 + 183) / 184 * 184 - 14;
-
-+ ts->tsid = ts->transport_stream_id;
-+ ts->onid = ts->original_network_id;
- if (!s->nb_programs) {
- /* allocate a single DVB service */
-- if (!mpegts_add_service(s, ts->service_id, s->metadata, NULL))
-+ title = av_dict_get(s->metadata, "service_name", NULL, 0);
-+ if (!title)
-+ title = av_dict_get(s->metadata, "title", NULL, 0);
-+ service_name = title ? title->value : DEFAULT_SERVICE_NAME;
-+ provider = av_dict_get(s->metadata, "service_provider", NULL, 0);
-+ provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME;
-+ service = mpegts_add_service(s, ts->service_id,
-+ provider_name, service_name);
-+
-+ if (!service)
- return AVERROR(ENOMEM);
-+
-+ service->pmt.write_packet = section_write_packet;
-+ service->pmt.opaque = s;
-+ service->pmt.cc = 15;
-+ service->pmt.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT;
- } else {
- for (i = 0; i < s->nb_programs; i++) {
- AVProgram *program = s->programs[i];
-- if (!mpegts_add_service(s, program->id, program->metadata, program))
-+ title = av_dict_get(program->metadata, "service_name", NULL, 0);
-+ if (!title)
-+ title = av_dict_get(program->metadata, "title", NULL, 0);
-+ service_name = title ? title->value : DEFAULT_SERVICE_NAME;
-+ provider = av_dict_get(program->metadata, "service_provider", NULL, 0);
-+ provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME;
-+ service = mpegts_add_service(s, program->id,
-+ provider_name, service_name);
-+
-+ if (!service)
- return AVERROR(ENOMEM);
-+
-+ service->pmt.write_packet = section_write_packet;
-+ service->pmt.opaque = s;
-+ service->pmt.cc = 15;
-+ service->pmt.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT;
-+ service->program = program;
- }
- }
-+ if (ts->m2ts_mode > 1)
-+ service->pmt.pid = 0x00ff + ts->service_id;
-
- ts->pat.pid = PAT_PID;
- /* Initialize at 15 so that it wraps and is equal to 0 for the
-@@ -991,158 +848,175 @@ static int mpegts_init(AVFormatContext *s)
- ts->sdt.write_packet = section_write_packet;
- ts->sdt.opaque = s;
-
-+ pids = av_malloc_array(s->nb_streams, sizeof(*pids));
-+ if (!pids) {
-+ ret = AVERROR(ENOMEM);
-+ goto fail;
-+ }
-+
- /* assign pids to each stream */
- for (i = 0; i < s->nb_streams; i++) {
-- AVStream *st = s->streams[i];
-- MpegTSWriteStream *ts_st;
-+ AVProgram *program;
-+ st = s->streams[i];
-
- ts_st = av_mallocz(sizeof(MpegTSWriteStream));
- if (!ts_st) {
-- return AVERROR(ENOMEM);
-+ ret = AVERROR(ENOMEM);
-+ goto fail;
- }
- st->priv_data = ts_st;
-
-+ ts_st->user_tb = st->time_base;
- avpriv_set_pts_info(st, 33, 1, 90000);
-
- ts_st->payload = av_mallocz(ts->pes_payload_size);
- if (!ts_st->payload) {
-- return AVERROR(ENOMEM);
-+ ret = AVERROR(ENOMEM);
-+ goto fail;
- }
-
-- /* MPEG pid values < 16 are reserved. Applications which set st->id in
-- * this range are assigned a calculated pid. */
-- if (st->id < 16) {
+@@ -1166,7 +1166,9 @@
+ /* MPEG pid values < 16 are reserved. Applications which set st->id in
+ * this range are assigned a calculated pid. */
+ if (st->id < 16) {
- if (ts->m2ts_mode) {
-- switch (st->codecpar->codec_type) {
-- case AVMEDIA_TYPE_VIDEO:
-- ts_st->pid = ts->m2ts_video_pid++;
-- break;
-- case AVMEDIA_TYPE_AUDIO:
-- ts_st->pid = ts->m2ts_audio_pid++;
-- break;
-- case AVMEDIA_TYPE_SUBTITLE:
-- switch (st->codecpar->codec_id) {
-- case AV_CODEC_ID_HDMV_PGS_SUBTITLE:
-- ts_st->pid = ts->m2ts_pgssub_pid++;
-- break;
-- case AV_CODEC_ID_HDMV_TEXT_SUBTITLE:
-- ts_st->pid = ts->m2ts_textsub_pid++;
-- break;
-- }
-+ program = av_find_program_from_stream(s, NULL, i);
-+ if (program) {
-+ for (j = 0; j < ts->nb_services; j++) {
-+ if (ts->services[j]->program == program) {
-+ service = ts->services[j];
- break;
++ if (ts->start_pid >= 0)
++ ts_st->pid = ts->start_pid + i;
++ else if (ts->m2ts_mode) {
+ switch (st->codecpar->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ ts_st->pid = ts->m2ts_video_pid++;
+@@ -1193,9 +1195,9 @@
+ av_log(s, AV_LOG_ERROR, "Cannot automatically assign PID for stream %d\n", st->index);
+ return AVERROR(EINVAL);
}
-- if (ts->m2ts_video_pid > M2TS_VIDEO_PID + 1 ||
-- ts->m2ts_audio_pid > M2TS_AUDIO_START_PID + 32 ||
-- ts->m2ts_pgssub_pid > M2TS_PGSSUB_START_PID + 32 ||
-- ts->m2ts_textsub_pid > M2TS_TEXTSUB_PID + 1 ||
-- ts_st->pid < 16) {
-- av_log(s, AV_LOG_ERROR, "Cannot automatically assign PID for stream %d\n", st->index);
-- return AVERROR(EINVAL);
-- }
- } else {
- ts_st->pid = ts->start_pid + i;
}
-- } else {
-- ts_st->pid = st->id;
- }
-- if (ts_st->pid >= 0x1FFF) {
-+
-+ ts_st->service = service;
-+ /* MPEG pid values < 16 are reserved. Applications which set st->id in
-+ * this range are assigned a calculated pid. */
-+ if (st->id < 16) {
-+ ts_st->pid = ts->start_pid + i;
-+ } else if (st->id < 0x1FFF) {
-+ ts_st->pid = st->id;
-+ } else {
- av_log(s, AV_LOG_ERROR,
- "Invalid stream id %d, must be less than 8191\n", st->id);
-- return AVERROR(EINVAL);
-+ ret = AVERROR(EINVAL);
-+ goto fail;
- }
-- for (j = 0; j < ts->nb_services; j++) {
-- if (ts->services[j]->pmt.pid > LAST_OTHER_PID) {
-- av_log(s, AV_LOG_ERROR,
-- "Invalid PMT PID %d, must be less than %d\n", ts->services[j]->pmt.pid, LAST_OTHER_PID + 1);
-- return AVERROR(EINVAL);
-- }
-- if (ts_st->pid == ts->services[j]->pmt.pid) {
-- av_log(s, AV_LOG_ERROR, "PID %d cannot be both elementary and PMT PID\n", ts_st->pid);
-- return AVERROR(EINVAL);
-- }
-+ if (ts_st->pid == service->pmt.pid) {
-+ av_log(s, AV_LOG_ERROR, "Duplicate stream id %d\n", ts_st->pid);
-+ ret = AVERROR(EINVAL);
-+ goto fail;
- }
- for (j = 0; j < i; j++) {
-- MpegTSWriteStream *ts_st_prev = s->streams[j]->priv_data;
-- if (ts_st_prev->pid == ts_st->pid) {
-+ if (pids[j] == ts_st->pid) {
- av_log(s, AV_LOG_ERROR, "Duplicate stream id %d\n", ts_st->pid);
-- return AVERROR(EINVAL);
-+ ret = AVERROR(EINVAL);
-+ goto fail;
- }
- }
-+ pids[i] = ts_st->pid;
- ts_st->payload_pts = AV_NOPTS_VALUE;
- ts_st->payload_dts = AV_NOPTS_VALUE;
- ts_st->first_pts_check = 1;
- ts_st->cc = 15;
- ts_st->discontinuity = ts->flags & MPEGTS_FLAG_DISCONT;
-+ /* update PCR pid by using the first video stream */
-+ if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
-+ service->pcr_sid == 0x1fff)
-+ pcr_st = st;
-+
- if (st->codecpar->codec_id == AV_CODEC_ID_AAC &&
- st->codecpar->extradata_size > 0) {
- AVStream *ast;
- ts_st->amux = avformat_alloc_context();
- if (!ts_st->amux) {
-- return AVERROR(ENOMEM);
-+ ret = AVERROR(ENOMEM);
-+ goto fail;
- }
- ts_st->amux->oformat =
- av_guess_format((ts->flags & MPEGTS_FLAG_AAC_LATM) ? "latm" : "adts",
- NULL, NULL);
- if (!ts_st->amux->oformat) {
-- return AVERROR(EINVAL);
-+ ret = AVERROR(EINVAL);
-+ goto fail;
- }
- if (!(ast = avformat_new_stream(ts_st->amux, NULL))) {
-- return AVERROR(ENOMEM);
-+ ret = AVERROR(ENOMEM);
-+ goto fail;
- }
- ret = avcodec_parameters_copy(ast->codecpar, st->codecpar);
- if (ret != 0)
-- return ret;
-+ goto fail;
- ast->time_base = st->time_base;
- ret = avformat_write_header(ts_st->amux, NULL);
- if (ret < 0)
-- return ret;
-+ goto fail;
- }
- if (st->codecpar->codec_id == AV_CODEC_ID_OPUS) {
- ts_st->opus_pending_trim_start = st->codecpar->initial_padding * 48000 / st->codecpar->sample_rate;
++ else
++ ts_st->pid = START_PID + i;
+ } else {
+ ts_st->pid = st->id;
}
- }
-
-+ av_freep(&pids);
-+
-+ /* if no video stream, use the first stream as PCR */
-+ if (!pcr_st && s->nb_streams > 0)
-+ pcr_st = s->streams[0];
-+ if (!pcr_st) {
-+ av_log(s, AV_LOG_ERROR, "no streams\n");
-+ ret = AVERROR(EINVAL);
-+ goto fail;
-+ }
-+ ts_st = pcr_st->priv_data;
-+ if (service->pcr_sid == 0x1fff)
-+ service->pcr_sid = ts_st->pid;
-+ if (service->pcr_pid == 0x1fff)
-+ service->pcr_pid = ts->m2ts_mode > 1 ?
-+ 0x1000 + ts->service_id : service->pcr_sid ;
-+ if (service->pmt.pid == service->pcr_pid) {
-+ av_log(s, AV_LOG_ERROR, "Duplicate stream id %d\n", service->pcr_pid);
-+ ret = AVERROR(EINVAL);
-+ goto fail;
-+ }
-+
-+ clk_rate = ts->mux_rate > 1 ? ts->mux_rate : PCR_TIME_BASE;
-+ ts->sdt_packet_period = ts->sdt_period < 0 ? -1 : ts->sdt_period/1000 * clk_rate;
-+ ts->pat_packet_period = ts->pat_period/1000 * clk_rate;
-+ service->pcr_packet_period = ts->pcr_period/1000 * clk_rate;
-+ if (service->pcr_packet_period < (TS_PACKET_SIZE*8*10))
-+ service->pcr_packet_period = (TS_PACKET_SIZE*8*10);
-+ av_log(s, AV_LOG_VERBOSE, "clk_rate %f: ticks/pkt %d pcr, %d sdt, %d pmt\n", clk_rate,
-+ (int)service->pcr_packet_period, (int)ts->sdt_packet_period, (int)ts->pat_packet_period);
-+
- if (ts->copyts < 1)
- ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, AV_TIME_BASE);
-
-- select_pcr_streams(s);
--
-- ts->last_pat_ts = AV_NOPTS_VALUE;
-- ts->last_sdt_ts = AV_NOPTS_VALUE;
+@@ -1263,9 +1265,14 @@
+ 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);
-+ // output a PCR as soon as possible
+- ts->nit_period = av_rescale(ts->nit_period_us, PCR_TIME_BASE, AV_TIME_BASE);
++ ts->pat_period = ts->pat_period_us < 0 ? -1 :
++ av_rescale(ts->pat_period_us, PCR_TIME_BASE, AV_TIME_BASE);
++ ts->sdt_period = ts->sdt_period_us < 0 ? -1 :
++ av_rescale(ts->sdt_period_us, PCR_TIME_BASE, AV_TIME_BASE);
++ ts->nit_period = ts->nit_period_us < 0 ? -1 :
++ av_rescale(ts->nit_period_us, PCR_TIME_BASE, AV_TIME_BASE);
+ ts->pcr = 0;
-+ service->pcr_packet_timer = 0;
-+ ts->pat_packet_timer = 0;
-+ ts->sdt_packet_timer = 0;
++ ts->pcr_pos = 0;
- if (ts->mux_rate == 1)
- av_log(s, AV_LOG_VERBOSE, "muxrate VBR, ");
- else
+ /* assign provider name */
+ provider = av_dict_get(s->metadata, "service_provider", NULL, 0);
+@@ -1281,8 +1288,8 @@
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",
+ 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));
-
- return 0;
-+
-+fail:
-+ av_freep(&pids);
-+ return ret;
++ ts->sdt_period < 0 ? -1 : av_rescale(ts->sdt_period, 1000, PCR_TIME_BASE),
++ ts->pat_period < 0 ? -1 : 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");
+@@ -1291,36 +1298,40 @@
}
- /* send SDT, PAT and PMT tables regularly */
--static void retransmit_si_info(AVFormatContext *s, int force_pat, int force_sdt, int64_t pcr)
-+static void retransmit_si_info(AVFormatContext *s, int force_pat, int64_t dts)
+ /* 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)
++static void retransmit_si_info(AVFormatContext *s, int force_pat, int force_sdt, int force_nit)
{
MpegTSWrite *ts = s->priv_data;
int i;
- ) {
- if (pcr != AV_NOPTS_VALUE)
- ts->last_sdt_ts = FFMAX(pcr, ts->last_sdt_ts);
-+ if ( ts->sdt_packet_period >= 0 && ts->pcr >= ts->sdt_packet_timer ) {
-+ ts->sdt_packet_timer = ts->pcr + ts->sdt_packet_period;
- mpegts_write_sdt(s);
- }
+- mpegts_write_sdt(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) {
- if (pcr != AV_NOPTS_VALUE)
- ts->last_pat_ts = FFMAX(pcr, ts->last_pat_ts);
-+ if (ts->pcr >= ts->pat_packet_timer || force_pat) {
-+ ts->pat_packet_timer = ts->pcr + ts->pat_packet_period;
- mpegts_write_pat(s);
- for (i = 0; i < ts->nb_services; i++)
- mpegts_write_pmt(s, ts->services[i]);
-@@ -1175,7 +1049,8 @@ static void mpegts_insert_null_packet(AVFormatContext *s)
- *q++ = 0xff;
- *q++ = 0x10;
- memset(q, 0x0FF, TS_PACKET_SIZE - (q - buf));
-- write_packet(s, buf);
-+ mpegts_prefix_m2ts_header(s);
-+ avio_write(s->pb, buf, TS_PACKET_SIZE);
+- mpegts_write_pat(s);
+- for (i = 0; i < ts->nb_services; i++)
+- mpegts_write_pmt(s, ts->services[i]);
+- }
+- 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->sdt_period >= 0) {
++ int64_t pcr = get_pcr(ts, s->pb);
++ if (ts->last_sdt_ts == AV_NOPTS_VALUE || pcr >= ts->last_sdt_ts + ts->sdt_period)
++ force_sdt = 1;
++ if (force_sdt) {
++ ts->last_sdt_ts = pcr;
++ mpegts_write_sdt(s);
++ }
++ }
++ if (ts->pat_period >= 0) {
++ int64_t pcr = get_pcr(ts, s->pb);
++ if (ts->last_pat_ts == AV_NOPTS_VALUE || pcr >= ts->last_pat_ts + ts->pat_period)
++ force_pat = 1;
++ if (force_pat) {
++ ts->last_pat_ts = pcr;
++ mpegts_write_pat(s);
++ for (i = 0; i < ts->nb_services; i++)
++ mpegts_write_pmt(s, ts->services[i]);
++ }
++ }
++ if (ts->nit_period >= 0) {
++ int64_t pcr = get_pcr(ts, s->pb);
++ if (ts->last_nit_ts == AV_NOPTS_VALUE || pcr >= ts->last_nit_ts + ts->nit_period)
++ force_nit = 1;
++ if (force_nit) {
++ ts->last_nit_ts = pcr;
+ if (ts->flags & MPEGTS_FLAG_NIT)
+ mpegts_write_nit(s);
++ }
+ }
}
- /* Write a single transport stream packet with a PCR and no payload */
-@@ -1183,13 +1058,14 @@ static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st)
+@@ -1357,25 +1368,29 @@
+ static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st)
{
MpegTSWrite *ts = s->priv_data;
- MpegTSWriteStream *ts_st = st->priv_data;
-+ uint32_t pcr_pid = ts_st->service->pcr_pid;
+- MpegTSWriteStream *ts_st = st->priv_data;
++ int64_t pcr = get_pcr(ts, s->pb);
++ MpegTSWriteStream *ts_st = st ? st->priv_data : 0;
++ uint32_t pcr_pid = ts_st ? ts_st->pid : ts->pcr_stream_pid;
uint8_t *q;
uint8_t buf[TS_PACKET_SIZE];
*q++ = 0x47;
- *q++ = ts_st->pid >> 8;
- *q++ = ts_st->pid;
+- *q++ = 0x20 | ts_st->cc; /* Adaptation only */
+ *q++ = pcr_pid >> 8;
+ *q++ = pcr_pid;
- *q++ = 0x20 | ts_st->cc; /* Adaptation only */
++ uint32_t flags = 0x20; /* Adaptation only */
/* Continuity Count field does not increment (see 13818-1 section 2.4.3.3) */
++ if(ts_st) flags |= ts_st->cc;
++ *q++ = flags;
*q++ = TS_PACKET_SIZE - 5; /* Adaptation Field Length */
-@@ -1200,11 +1076,12 @@ static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st)
+ *q++ = 0x10; /* Adaptation flags: PCR present */
+- if (ts_st->discontinuity) {
++ if (ts_st && ts_st->discontinuity) {
+ q[-1] |= 0x80;
+ ts_st->discontinuity = 0;
}
/* PCR coded into 6 bytes */
-- q += write_pcr_bits(q, get_pcr(ts, s->pb));
-+ q += write_pcr_bits(q, ts->pcr);
+- q += write_pcr_bits(q, get_pcr(ts));
++ q += write_pcr_bits(q, pcr);
/* stuffing bytes */
memset(q, 0xFF, TS_PACKET_SIZE - (q - buf));
-- write_packet(s, buf);
-+ mpegts_prefix_m2ts_header(s);
-+ avio_write(s->pb, buf, TS_PACKET_SIZE);
- }
-
- static void write_pts(uint8_t *q, int fourbits, int64_t pts)
-@@ -1268,84 +1145,55 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
- uint8_t *q;
- int val, is_start, len, header_len, write_pcr, is_dvb_subtitle, is_dvb_teletext, flags;
+@@ -1475,9 +1490,9 @@
int afc_len, stuffing_len;
+ int is_dvb_subtitle = (st->codecpar->codec_id == AV_CODEC_ID_DVB_SUBTITLE);
+ int is_dvb_teletext = (st->codecpar->codec_id == AV_CODEC_ID_DVB_TELETEXT);
- 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_sdt = 0;
++ int64_t pcr;
+ 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) {
- force_pat = 1;
- }
+@@ -1494,21 +1509,19 @@
-- if (ts->flags & MPEGTS_FLAG_REEMIT_PAT_PMT) {
-- force_pat = 1;
-- force_sdt = 1;
-- ts->flags &= ~MPEGTS_FLAG_REEMIT_PAT_PMT;
-- }
--
is_start = 1;
while (payload_size > 0) {
- int64_t pcr = AV_NOPTS_VALUE;
- if (ts->mux_rate > 1)
-- pcr = get_pcr(ts, s->pb);
+- pcr = get_pcr(ts);
- else if (dts != AV_NOPTS_VALUE)
- pcr = (dts - delay) * 300;
-+ ts->pcr = ts->first_pcr + (ts->mux_rate == 1 ?
-+ (dts == AV_NOPTS_VALUE ? 0 : (dts - ts->delay) * 300) :
-+ // add 11, pcr references the last byte of program clock reference base
-+ av_rescale(avio_tell(s->pb) + 11, 8 * PCR_TIME_BASE, ts->mux_rate));
-
-- retransmit_si_info(s, force_pat, force_sdt, pcr);
-+ retransmit_si_info(s, force_pat, dts);
- force_pat = 0;
+-
+- retransmit_si_info(s, force_pat, force_sdt, force_nit, pcr);
+- force_pat = 0;
- force_sdt = 0;
+- force_nit = 0;
++ // add 11, pcr references the last byte of program clock reference base
++ ts->pcr_pos = avio_tell(s->pb) + 11;
++ pcr = ts->pcr = ts->mux_rate != 1 ?
++ av_rescale(ts->pcr_pos, 8 * PCR_TIME_BASE, ts->mux_rate) :
++ (dts == AV_NOPTS_VALUE ? 0 : (dts - ts->delay) * 300);
++ if (force_pat || force_sdt || force_nit) {
++ retransmit_si_info(s, force_pat, force_sdt, force_nit);
++ force_pat = force_sdt = force_nit = 0;
++ }
write_pcr = 0;
-- if (ts->mux_rate > 1) {
-- /* Send PCR packets for all PCR streams if needed */
-- pcr = get_pcr(ts, s->pb);
-- if (pcr >= ts->next_pcr) {
-- int64_t next_pcr = INT64_MAX;
-- 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 */
-- int st2_index = i < st->index ? i : (i + 1 == s->nb_streams ? st->index : i + 1);
-- AVStream *st2 = s->streams[st2_index];
-- MpegTSWriteStream *ts_st2 = st2->priv_data;
-- if (ts_st2->pcr_period) {
+ if (ts->mux_rate > 1) {
+ /* Send PCR packets for all PCR streams if needed */
+- pcr = get_pcr(ts);
+ if (pcr >= ts->next_pcr) {
+ int64_t next_pcr = INT64_MAX;
+ for (int i = 0; i < s->nb_streams; i++) {
+@@ -1518,36 +1531,43 @@
+ AVStream *st2 = s->streams[st2_index];
+ MpegTSWriteStream *ts_st2 = st2->priv_data;
+ if (ts_st2->pcr_period) {
- 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);
-- pcr = get_pcr(ts, s->pb);
-- } else {
-- write_pcr = 1;
-- }
-- }
++ if (pcr >= ts_st2->pcr_timer) {
++ ts_st2->pcr_timer = pcr + ts_st2->pcr_period;
++ if (st2 != st) {
+ mpegts_insert_pcr_only(s, st2);
+- pcr = get_pcr(ts);
+ } else {
+ write_pcr = 1;
+ }
+ }
- next_pcr = FFMIN(next_pcr, ts_st2->last_pcr + ts_st2->pcr_period);
-- }
-- }
-- ts->next_pcr = next_pcr;
-- }
++ next_pcr = FFMIN(next_pcr, ts_st2->pcr_timer);
+ }
+ }
+ 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)
- } else if (ts_st->pcr_period && pcr != AV_NOPTS_VALUE) {
- if (pcr - ts_st->last_pcr >= ts_st->pcr_period && is_start) {
- ts_st->last_pcr = FFMAX(pcr - ts_st->pcr_period, ts_st->last_pcr + ts_st->pcr_period);
-+ if (ts_st->pid == ts_st->service->pcr_sid) {
-+ if( ts->pcr >= ts_st->service->pcr_packet_timer ) {
-+ ts_st->service->pcr_packet_timer = ts->pcr + ts_st->service->pcr_packet_period;
++ }
++ else if (ts_st->pcr_period) {
++ if (pcr >= ts_st->pcr_timer) {
++ ts_st->pcr_timer = pcr + ts_st->pcr_period;
write_pcr = 1;
}
}
-+ if (write_pcr && ts_st->service->pcr_sid != ts_st->service->pcr_pid) {
-+ mpegts_insert_pcr_only(s, st);
+
++ if (write_pcr && ts->pcr_stream_pid >= 0) {
++ mpegts_insert_pcr_only(s, 0);
+ continue;
+ }
++
+ if (ts->mux_rate > 1 && dts != AV_NOPTS_VALUE &&
-+ (dts - ts->pcr / 300) > ts->delay) {
++ (dts - pcr / 300) > ts->delay) {
+ /* pcr insert gets priority over null packet insert */
+ if (write_pcr)
+ mpegts_insert_pcr_only(s, st);
+ /* recalculate write_pcr and possibly retransimit si_info */
+ continue;
+ }
-
++
/* prepare packet header */
q = buf;
*q++ = 0x47;
- val = ts_st->pid >> 8;
-- if (ts->m2ts_mode && st->codecpar->codec_id == AV_CODEC_ID_AC3)
-- val |= 0x20;
- if (is_start)
- val |= 0x40;
-+ if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
-+ st->codecpar->codec_id == AV_CODEC_ID_AC3 &&
-+ ts->m2ts_mode > 1)
-+ val |= 0x20;
- *q++ = val;
- *q++ = ts_st->pid;
- ts_st->cc = ts_st->cc + 1 & 0xf;
-@@ -1357,7 +1205,7 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
- }
- if (key && is_start && pts != AV_NOPTS_VALUE) {
- // set Random Access for key frames
-- if (ts_st->pcr_period)
-+ if (ts_st->pid == ts_st->service->pcr_sid)
- write_pcr = 1;
- set_af_flag(buf, 0x40);
- q = get_ts_payload_start(buf);
-@@ -1365,10 +1213,10 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
+@@ -1576,7 +1596,6 @@
if (write_pcr) {
set_af_flag(buf, 0x10);
q = get_ts_payload_start(buf);
- // add 11, pcr references the last byte of program clock reference base
-- if (dts != AV_NOPTS_VALUE && dts < pcr / 300)
-+ if (ts->mux_rate > 1)
-+ if (dts != AV_NOPTS_VALUE && dts < ts->pcr / 300)
+ if (dts != AV_NOPTS_VALUE && dts < pcr / 300)
av_log(s, AV_LOG_WARNING, "dts < pcr, TS is invalid\n");
-- extend_af(buf, write_pcr_bits(q, pcr));
-+ extend_af(buf, write_pcr_bits(q, ts->pcr));
- q = get_ts_payload_start(buf);
- }
- if (is_start) {
-@@ -1439,10 +1287,10 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
- if (ts->m2ts_mode &&
- st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
- st->codecpar->codec_id == AV_CODEC_ID_AC3) {
-- /* set PES_extension_flag */
-- pes_extension = 1;
-- flags |= 0x01;
-- header_len += 3;
-+ /* set PES_extension_flag */
-+ pes_extension = 1;
-+ flags |= 0x01;
-+ header_len += 3;
- }
- if (is_dvb_teletext) {
- pes_header_stuffing_bytes = 0x24 - header_len;
-@@ -1469,11 +1317,13 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
- *q++ = flags;
- *q++ = header_len;
- if (pts != AV_NOPTS_VALUE) {
-- write_pts(q, flags >> 6, pts);
-+ int64_t ts_pts = pts + ts->ts_offset;
-+ write_pts(q, flags >> 6, ts_pts);
- q += 5;
- }
- if (dts != AV_NOPTS_VALUE && pts != AV_NOPTS_VALUE && dts != pts) {
-- write_pts(q, 1, dts);
-+ int64_t ts_dts = dts + ts->ts_offset;
-+ write_pts(q, 1, ts_dts);
- q += 5;
- }
- if (pes_extension && st->codecpar->codec_id == AV_CODEC_ID_DIRAC) {
-@@ -1485,14 +1335,14 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
- *q++ = 0x00 | 0x60;
- }
- /* For Blu-ray AC3 Audio Setting extended flags */
-- if (ts->m2ts_mode &&
-- pes_extension &&
-- st->codecpar->codec_id == AV_CODEC_ID_AC3) {
-- flags = 0x01; /* set PES_extension_flag_2 */
-- *q++ = flags;
-- *q++ = 0x80 | 0x01; /* marker bit + extension length */
-- *q++ = 0x00 | 0x71; /* for AC3 Audio (specifically on blue-rays) */
-- }
-+ if (ts->m2ts_mode &&
-+ pes_extension &&
-+ st->codecpar->codec_id == AV_CODEC_ID_AC3) {
-+ flags = 0x01; /* set PES_extension_flag_2 */
-+ *q++ = flags;
-+ *q++ = 0x80 | 0x01; /* marker bit + extension length */
-+ *q++ = 0x00 | 0x71; /* for AC3 Audio (specifically on blue-rays) */
-+ }
-
-
- if (is_dvb_subtitle) {
-@@ -1546,7 +1396,8 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
-
- payload += len;
- payload_size -= len;
-- write_packet(s, buf);
-+ mpegts_prefix_m2ts_header(s);
-+ avio_write(s->pb, buf, TS_PACKET_SIZE);
- }
- ts_st->prev_payload_key = key;
- }
-@@ -1643,8 +1494,6 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
+ extend_af(buf, write_pcr_bits(q, pcr));
+@@ -1840,8 +1859,8 @@
uint8_t *data = NULL;
MpegTSWrite *ts = s->priv_data;
MpegTSWriteStream *ts_st = st->priv_data;
- const int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE) * 2;
- const int64_t max_audio_delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE) / 2;
++ const int64_t delay_ticks2 = ts->delay * 2;
++ const int64_t max_audio_delay = ts->delay / 2;
int64_t dts = pkt->dts, pts = pkt->pts;
int opus_samples = 0;
- int side_data_size;
-@@ -1657,11 +1506,23 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
- if (side_data)
- stream_id = side_data[0];
+ size_t side_data_size;
+@@ -1861,9 +1880,9 @@
-+ if (ts->reemit_pat_pmt) {
-+ av_log(s, AV_LOG_WARNING,
-+ "resend_headers option is deprecated, use -mpegts_flags resend_headers\n");
-+ ts->reemit_pat_pmt = 0;
-+ ts->flags |= MPEGTS_FLAG_REEMIT_PAT_PMT;
-+ }
-+
-+ if (ts->flags & MPEGTS_FLAG_REEMIT_PAT_PMT) {
-+ ts->pat_packet_timer = ts->sdt_packet_timer = 0;
-+ ts->flags &= ~MPEGTS_FLAG_REEMIT_PAT_PMT;
-+ }
-+
if (ts->copyts < 1) {
if (pts != AV_NOPTS_VALUE)
- pts += delay;
-+ pts += 2*ts->delay;
++ pts += delay_ticks2;
if (dts != AV_NOPTS_VALUE)
- dts += delay;
-+ dts += 2*ts->delay;
- }
-
- if (ts_st->first_pts_check && pts == AV_NOPTS_VALUE) {
-@@ -1724,7 +1585,7 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
-
- ret = avio_open_dyn_buf(&ts_st->amux->pb);
- if (ret < 0)
-- return ret;
-+ return AVERROR(ENOMEM);
-
- ret = av_write_frame(ts_st->amux, &pkt2);
- if (ret < 0) {
-@@ -1755,7 +1616,7 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
- } while (p < buf_end && (state & 0x7e) != 2*35 &&
- (state & 0x7e) >= 2*32);
-
-- if ((state & 0x7e) < 2*16 || (state & 0x7e) >= 2*24)
-+ if ((state & 0x7e) < 2*16 && (state & 0x7e) >= 2*24)
- extradd = 0;
- if ((state & 0x7e) != 2*35) { // AUD NAL
- data = av_malloc(pkt->size + 7 + extradd);
-@@ -1843,9 +1704,25 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
- }
++ dts += delay_ticks2;
}
-+ if (pkt->dts != AV_NOPTS_VALUE) {
-+ int i;
-+ for(i=0; i<s->nb_streams; i++) {
-+ AVStream *st2 = s->streams[i];
-+ MpegTSWriteStream *ts_st2 = st2->priv_data;
-+ if ( ts_st2->payload_size
-+ && (ts_st2->payload_dts == AV_NOPTS_VALUE || dts - ts_st2->payload_dts > ts->delay)) {
-+ mpegts_write_pes(s, st2, ts_st2->payload, ts_st2->payload_size,
-+ ts_st2->payload_pts, ts_st2->payload_dts,
-+ ts_st2->payload_flags & AV_PKT_FLAG_KEY, stream_id);
-+ ts_st2->payload_size = 0;
-+ }
-+ }
-+ }
-+
- if (ts_st->payload_size && (ts_st->payload_size + size > ts->pes_payload_size ||
- (dts != AV_NOPTS_VALUE && ts_st->payload_dts != AV_NOPTS_VALUE &&
-- dts - ts_st->payload_dts >= max_audio_delay) ||
-+ av_compare_ts(dts - ts_st->payload_dts, st->time_base,
-+ s->max_delay, AV_TIME_BASE_Q) >= 0) ||
- ts_st->opus_queued_samples + opus_samples >= 5760 /* 120ms */)) {
- mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_size,
- ts_st->payload_pts, ts_st->payload_dts,
-@@ -1881,7 +1758,6 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
-
- static void mpegts_write_flush(AVFormatContext *s)
- {
-- MpegTSWrite *ts = s->priv_data;
- int i;
-
- /* flush current packets */
-@@ -1896,12 +1772,6 @@ static void mpegts_write_flush(AVFormatContext *s)
- ts_st->opus_queued_samples = 0;
- }
- }
--
-- if (ts->m2ts_mode) {
-- int packets = (avio_tell(s->pb) / (TS_PACKET_SIZE + 4)) % 32;
-- while (packets++ < 32)
-- mpegts_insert_null_packet(s);
-- }
- }
-
- static int mpegts_write_packet(AVFormatContext *s, AVPacket *pkt)
-@@ -1969,62 +1839,104 @@ static int mpegts_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt
- return ret;
- }
-
--#define OFFSET(x) offsetof(MpegTSWrite, x)
--#define ENC AV_OPT_FLAG_ENCODING_PARAM
- static const AVOption options[] = {
- { "mpegts_transport_stream_id", "Set transport_stream_id field.",
-- OFFSET(transport_stream_id), AV_OPT_TYPE_INT, { .i64 = 0x0001 }, 0x0001, 0xffff, ENC },
-+ offsetof(MpegTSWrite, transport_stream_id), AV_OPT_TYPE_INT,
-+ { .i64 = 0x0001 }, 0x0001, 0xffff, AV_OPT_FLAG_ENCODING_PARAM },
- { "mpegts_original_network_id", "Set original_network_id field.",
-- OFFSET(original_network_id), AV_OPT_TYPE_INT, { .i64 = DVB_PRIVATE_NETWORK_START }, 0x0001, 0xffff, ENC },
-+ offsetof(MpegTSWrite, original_network_id), AV_OPT_TYPE_INT,
-+ { .i64 = DVB_PRIVATE_NETWORK_START }, 0x0001, 0xffff, AV_OPT_FLAG_ENCODING_PARAM },
- { "mpegts_service_id", "Set service_id field.",
-- OFFSET(service_id), AV_OPT_TYPE_INT, { .i64 = 0x0001 }, 0x0001, 0xffff, ENC },
-+ offsetof(MpegTSWrite, service_id), AV_OPT_TYPE_INT,
-+ { .i64 = 0x0001 }, 0x0001, 0xffff, AV_OPT_FLAG_ENCODING_PARAM },
- { "mpegts_service_type", "Set service_type field.",
-- OFFSET(service_type), AV_OPT_TYPE_INT, { .i64 = 0x01 }, 0x01, 0xff, ENC, "mpegts_service_type" },
-+ offsetof(MpegTSWrite, service_type), AV_OPT_TYPE_INT,
-+ { .i64 = 0x01 }, 0x01, 0xff, AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
- { "digital_tv", "Digital Television.",
-- 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_DIGITAL_TV }, 0x01, 0xff, ENC, "mpegts_service_type" },
-+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_DIGITAL_TV }, 0x01, 0xff,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
- { "digital_radio", "Digital Radio.",
-- 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_DIGITAL_RADIO }, 0x01, 0xff, ENC, "mpegts_service_type" },
-+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_DIGITAL_RADIO }, 0x01, 0xff,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
- { "teletext", "Teletext.",
-- 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_TELETEXT }, 0x01, 0xff, ENC, "mpegts_service_type" },
-+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_TELETEXT }, 0x01, 0xff,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
- { "advanced_codec_digital_radio", "Advanced Codec Digital Radio.",
-- 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_RADIO }, 0x01, 0xff, ENC, "mpegts_service_type" },
-+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_RADIO }, 0x01, 0xff,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
- { "mpeg2_digital_hdtv", "MPEG2 Digital HDTV.",
-- 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_MPEG2_DIGITAL_HDTV }, 0x01, 0xff, ENC, "mpegts_service_type" },
-+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_MPEG2_DIGITAL_HDTV }, 0x01, 0xff,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
- { "advanced_codec_digital_sdtv", "Advanced Codec Digital SDTV.",
-- 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_SDTV }, 0x01, 0xff, ENC, "mpegts_service_type" },
-+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_SDTV }, 0x01, 0xff,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
- { "advanced_codec_digital_hdtv", "Advanced Codec Digital HDTV.",
-- 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_HDTV }, 0x01, 0xff, ENC, "mpegts_service_type" },
-+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_HDTV }, 0x01, 0xff,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
- { "hevc_digital_hdtv", "HEVC Digital Television Service.",
-- 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_HEVC_DIGITAL_HDTV }, 0x01, 0xff, ENC, "mpegts_service_type" },
-+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_HEVC_DIGITAL_HDTV }, 0x01, 0xff,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
+ if (!ts_st->first_timestamp_checked && (pts == AV_NOPTS_VALUE || dts == AV_NOPTS_VALUE)) {
+@@ -2262,8 +2281,10 @@
+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_HEVC_DIGITAL_HDTV }, 0x01, 0xff, ENC, "mpegts_service_type" },
{ "mpegts_pmt_start_pid", "Set the first pid of the PMT.",
-- OFFSET(pmt_start_pid), AV_OPT_TYPE_INT, { .i64 = 0x1000 }, FIRST_OTHER_PID, LAST_OTHER_PID, ENC },
-+ offsetof(MpegTSWrite, pmt_start_pid), AV_OPT_TYPE_INT,
-+ { .i64 = 0x1000 }, 0x0010, 0x1f00, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "mpegts_pcr_start_pid", "Set the first pid of the PCR.",
-+ offsetof(MpegTSWrite, pcr_start_pid), AV_OPT_TYPE_INT,
-+ { .i64 = 0x1000 }, 0x0010, 0x1f00, AV_OPT_FLAG_ENCODING_PARAM },
+ OFFSET(pmt_start_pid), AV_OPT_TYPE_INT, { .i64 = 0x1000 }, FIRST_OTHER_PID, LAST_OTHER_PID, ENC },
++ { "mpegts_pcr_stream_pid", "create seperate PCR stream on this pid.",
++ OFFSET(pcr_stream_pid), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 0x1f00, ENC },
{ "mpegts_start_pid", "Set the first pid.",
- OFFSET(start_pid), AV_OPT_TYPE_INT, { .i64 = 0x0100 }, FIRST_OTHER_PID, LAST_OTHER_PID, ENC },
-- { "mpegts_m2ts_mode", "Enable m2ts mode.", OFFSET(m2ts_mode), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, ENC },
-- { "muxrate", NULL, OFFSET(mux_rate), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, ENC },
-+ offsetof(MpegTSWrite, start_pid), AV_OPT_TYPE_INT,
-+ { .i64 = 0x0100 }, 0x0010, 0x0f00, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "mpegts_m2ts_mode", "Enable m2ts mode.",
-+ offsetof(MpegTSWrite, m2ts_mode), AV_OPT_TYPE_BOOL,
-+ { .i64 = -1 }, -1, 2, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "mpegts_pcr_offset", "clock offset.",
-+ offsetof(MpegTSWrite, ts_offset), AV_OPT_TYPE_BOOL,
-+ { .i64 = 0 }, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "muxrate", NULL,
-+ offsetof(MpegTSWrite, mux_rate), AV_OPT_TYPE_INT,
-+ { .i64 = 1 }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
++ OFFSET(start_pid), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, LAST_OTHER_PID, ENC },
+ { "mpegts_m2ts_mode", "Enable m2ts mode.", OFFSET(m2ts_mode), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, ENC },
+ { "muxrate", NULL, OFFSET(mux_rate), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, ENC },
{ "pes_payload_size", "Minimum PES packet payload in bytes",
-- OFFSET(pes_payload_size), AV_OPT_TYPE_INT, { .i64 = DEFAULT_PES_PAYLOAD_SIZE }, 0, INT_MAX, ENC },
-- { "mpegts_flags", "MPEG-TS muxing flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, 0, INT_MAX, ENC, "mpegts_flags" },
-+ offsetof(MpegTSWrite, pes_payload_size), AV_OPT_TYPE_INT,
-+ { .i64 = DEFAULT_PES_PAYLOAD_SIZE }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "mpegts_flags", "MPEG-TS muxing flags",
-+ offsetof(MpegTSWrite, flags), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, 0, INT_MAX,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" },
- { "resend_headers", "Reemit PAT/PMT before writing the next packet",
-- 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_REEMIT_PAT_PMT }, 0, INT_MAX, ENC, "mpegts_flags" },
-+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_REEMIT_PAT_PMT }, 0, INT_MAX,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" },
- { "latm", "Use LATM packetization for AAC",
-- 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_AAC_LATM }, 0, INT_MAX, ENC, "mpegts_flags" },
-+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_AAC_LATM }, 0, INT_MAX,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" },
- { "pat_pmt_at_frames", "Reemit PAT and PMT at each video frame",
-- 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_PAT_PMT_AT_FRAMES}, 0, INT_MAX, ENC, "mpegts_flags" },
-+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_PAT_PMT_AT_FRAMES}, 0, INT_MAX,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" },
- { "system_b", "Conform to System B (DVB) instead of System A (ATSC)",
-- 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_SYSTEM_B }, 0, INT_MAX, ENC, "mpegts_flags" },
-+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_SYSTEM_B }, 0, INT_MAX,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" },
- { "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 },
-+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_DISCONT }, 0, INT_MAX,
-+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" },
-+ // backward compatibility
-+ { "resend_headers", "Reemit PAT/PMT before writing the next packet",
-+ offsetof(MpegTSWrite, reemit_pat_pmt), AV_OPT_TYPE_INT,
-+ { .i64 = 0 }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "mpegts_copyts", "don't offset dts/pts",
-+ offsetof(MpegTSWrite, copyts), AV_OPT_TYPE_BOOL,
-+ { .i64 = -1 }, -1, 1, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "tables_version", "set PAT, PMT and SDT version",
-+ offsetof(MpegTSWrite, tables_version), AV_OPT_TYPE_INT,
-+ { .i64 = 0 }, 0, 31, AV_OPT_FLAG_ENCODING_PARAM },
- { "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",
-- OFFSET(pcr_period_ms), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, ENC },
+@@ -2287,10 +2308,10 @@
+ OFFSET(omit_video_pes_length), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, ENC },
+ { "pcr_period", "PCR retransmission time in milliseconds",
+ OFFSET(pcr_period_ms), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, ENC },
- { "pat_period", "PAT/PMT retransmission time limit in seconds",
-- OFFSET(pat_period_us), AV_OPT_TYPE_DURATION, { .i64 = PAT_RETRANS_TIME * 1000LL }, 0, INT64_MAX, ENC },
++ { "pat_period", "PAT/PMT retransmission time limit in ms, -1 no pat",
+ 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 },
-+ offsetof(MpegTSWrite, omit_video_pes_length), AV_OPT_TYPE_BOOL,
-+ { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "pcr_period", "PCR retransmission time limit in msecs",
-+ offsetof(MpegTSWrite, pcr_period), AV_OPT_TYPE_DOUBLE,
-+ { .dbl = PCR_RETRANS_TIME }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "pat_period", "PAT/PMT retransmission time limit in msecs",
-+ offsetof(MpegTSWrite, pat_period), AV_OPT_TYPE_DOUBLE,
-+ { .dbl = PAT_RETRANS_TIME }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
-+ { "sdt_period", "SDT retransmission time limit in msecs",
-+ offsetof(MpegTSWrite, sdt_period), AV_OPT_TYPE_DOUBLE,
-+ { .dbl = SDT_RETRANS_TIME }, -1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
++ { "sdt_period", "SDT retransmission time limit in ms, -1 no sdt",
++ OFFSET(sdt_period_us), AV_OPT_TYPE_INT64, { .i64 = SDT_RETRANS_TIME * 1000LL }, -1, 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 },
{ NULL },
- };
-
+--- a/libavformat/mpegts.h
++++ b/libavformat/mpegts.h
+@@ -64,6 +64,7 @@
+ /* PID from 0x1FFC to 0x1FFE may be assigned as needed to PMT, elementary
+ * streams and other data tables */
+ #define NULL_PID 0x1FFF /* Null packet (used for fixed bandwidth padding) */
++#define START_PID 0x0400
+
+ /* m2ts pids */
+ #define M2TS_PMT_PID 0x0100
+--- a/libavformat/bluray.c
++++ b/libavformat/bluray.c
+@@ -28,7 +28,7 @@
+ #include "libavutil/opt.h"
+
+ #define BLURAY_PROTO_PREFIX "bluray:"
+-#define MIN_PLAYLIST_LENGTH 180 /* 3 min */
++#define MIN_PLAYLIST_LENGTH 0
+
+ typedef struct {
+ const AVClass *class;
+--- a/doc/muxers.texi
++++ b/doc/muxers.texi
+@@ -1934,7 +1934,8 @@
+ 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}.