X-Git-Url: https://git.cinelerra-gg.org/git/?p=goodguy%2Fcinelerra.git;a=blobdiff_plain;f=cinelerra-5.1%2Fthirdparty%2Fsrc%2Fffmpeg-4.3.patch2;fp=cinelerra-5.1%2Fthirdparty%2Fsrc%2Fffmpeg-4.3.patch2;h=81cae5e66d85d3c089603a5a6425cd165aa9f16e;hp=0000000000000000000000000000000000000000;hb=d830901b11606a7838791bc45e39130329db99f0;hpb=fa27f905f12b15ae84eb1b3ffcd12e09d6d02660 diff --git a/cinelerra-5.1/thirdparty/src/ffmpeg-4.3.patch2 b/cinelerra-5.1/thirdparty/src/ffmpeg-4.3.patch2 new file mode 100644 index 00000000..81cae5e6 --- /dev/null +++ b/cinelerra-5.1/thirdparty/src/ffmpeg-4.3.patch2 @@ -0,0 +1,1335 @@ +diff -u a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c +--- a/libavformat/mpegtsenc.c 2020-06-15 12:54:24.000000000 -0600 ++++ b/libavformat/mpegtsenc.c 2020-07-10 11:21:45.303839343 -0600 +@@ -56,7 +56,8 @@ + 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 @@ + 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; + int nb_services; +- int64_t first_pcr; +- int64_t next_pcr; ++ int onid; ++ int tsid; ++ int64_t pcr, first_pcr, delay; + int mux_rate; ///< set to 1 when VBR + int pes_payload_size; + +@@ -90,14 +92,14 @@ + 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 @@ + 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 @@ + /* 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 @@ + int payload_flags; + uint8_t *payload; + AVFormatContext *amux; +- int data_st_warning; +- +- int64_t pcr_period; /* PCR period in PCR time base */ +- int64_t last_pcr; ++ AVRational user_tb; + + /* For Opus */ + int opus_queued_samples; +@@ -259,7 +257,7 @@ + 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 @@ + *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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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) + { + 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 @@ + 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; + } + +-static void enable_pcr_generation_for_stream(AVFormatContext *s, AVStream *pcr_st) ++static void mpegts_prefix_m2ts_header(AVFormatContext *s) + { + 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)); + } +- +- // 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; + ++ 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 @@ + } + } + +- 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 @@ + 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) { +- if (ts->m2ts_mode) { +- switch (st->codecpar->codec_type) { +- case AVMEDIA_TYPE_VIDEO: +- ts_st->pid = ts->m2ts_video_pid++; ++ 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; +- 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; +- } +- break; +- } +- 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; + } + } + ++ 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; +- 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->pcr = 0; ++ service->pcr_packet_timer = 0; ++ ts->pat_packet_timer = 0; ++ ts->sdt_packet_timer = 0; + + if (ts->mux_rate == 1) + av_log(s, AV_LOG_VERBOSE, "muxrate VBR, "); + else + av_log(s, AV_LOG_VERBOSE, "muxrate %d, ", ts->mux_rate); +- av_log(s, AV_LOG_VERBOSE, +- "sdt every %"PRId64" ms, pat/pmt every %"PRId64" ms\n", +- 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; + } + + /* 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) + { + MpegTSWrite *ts = s->priv_data; + int i; + +- if ((pcr != AV_NOPTS_VALUE && ts->last_sdt_ts == AV_NOPTS_VALUE) || +- (pcr != AV_NOPTS_VALUE && pcr - ts->last_sdt_ts >= ts->sdt_period) || +- force_sdt +- ) { +- 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); + } +- 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 @@ + *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); + } + + /* Write a single transport stream packet with a PCR and no payload */ +@@ -1183,13 +1058,14 @@ + { + MpegTSWrite *ts = s->priv_data; + MpegTSWriteStream *ts_st = st->priv_data; ++ uint32_t pcr_pid = ts_st->service->pcr_pid; + uint8_t *q; + uint8_t buf[TS_PACKET_SIZE]; + + q = buf; + *q++ = 0x47; +- *q++ = ts_st->pid >> 8; +- *q++ = ts_st->pid; ++ *q++ = pcr_pid >> 8; ++ *q++ = pcr_pid; + *q++ = 0x20 | ts_st->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 */ +@@ -1200,11 +1076,12 @@ + } + + /* PCR coded into 6 bytes */ +- q += write_pcr_bits(q, get_pcr(ts, s->pb)); ++ q += write_pcr_bits(q, ts->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 @@ + uint8_t *q; + int val, is_start, len, header_len, write_pcr, is_dvb_subtitle, is_dvb_teletext, flags; + int afc_len, stuffing_len; +- 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; + + 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; + } + +- 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); +- 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; +- force_sdt = 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 (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; +- } +- } +- 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); +- else +- mpegts_insert_null_packet(s); +- /* recalculate write_pcr and possibly retransmit si_info */ +- continue; +- } +- } 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; + write_pcr = 1; + } + } ++ if (write_pcr && ts_st->service->pcr_sid != ts_st->service->pcr_pid) { ++ mpegts_insert_pcr_only(s, st); ++ continue; ++ } ++ if (ts->mux_rate > 1 && dts != AV_NOPTS_VALUE && ++ (dts - ts->pcr / 300) > ts->delay) { ++ /* pcr insert gets priority over null packet insert */ ++ if (write_pcr) ++ mpegts_insert_pcr_only(s, st); ++ else ++ mpegts_insert_null_packet(s); ++ /* 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 @@ + } + 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 @@ + 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) + 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 @@ + 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 @@ + *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 @@ + *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 @@ + + 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 @@ + 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; + int64_t dts = pkt->dts, pts = pkt->pts; + int opus_samples = 0; + int side_data_size; +@@ -1657,11 +1506,23 @@ + if (side_data) + stream_id = side_data[0]; + ++ 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; + 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 @@ + + 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 @@ + } 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 @@ + } + } + ++ if (pkt->dts != AV_NOPTS_VALUE) { ++ int i; ++ for(i=0; inb_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 void mpegts_write_flush(AVFormatContext *s) + { +- MpegTSWrite *ts = s->priv_data; + int i; + + /* flush current packets */ +@@ -1896,12 +1772,6 @@ + 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 @@ + 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" }, + { "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 }, + { "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 }, + { "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 }, +- { "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 }, +- { "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 }, + { NULL }, + }; +