X-Git-Url: https://git.cinelerra-gg.org/git/?a=blobdiff_plain;f=cinelerra-5.1%2Fthirdparty%2Fsrc%2Fffmpeg.git.patch2;h=11573c26c08195a13541ba1b7460a46cbfba4869;hb=863a0e2669ef76750ed76d71dedac96b70268c63;hp=e05f3372b15df8897a11cac48b667b2623393e48;hpb=7fd85fb66168f6b518c5f2d73e04036e87faa0e1;p=goodguy%2Fcinelerra.git diff --git a/cinelerra-5.1/thirdparty/src/ffmpeg.git.patch2 b/cinelerra-5.1/thirdparty/src/ffmpeg.git.patch2 index e05f3372..11573c26 100644 --- a/cinelerra-5.1/thirdparty/src/ffmpeg.git.patch2 +++ b/cinelerra-5.1/thirdparty/src/ffmpeg.git.patch2 @@ -1,64 +1,73 @@ -diff -urN a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c ---- a/libavformat/mpegtsenc.c 2018-04-20 04:02:57.000000000 -0600 -+++ b/libavformat/mpegtsenc.c 2018-04-24 10:27:57.193689213 -0600 -@@ -56,9 +56,8 @@ +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 */ - char *name; - char *provider_name; + uint8_t name[256]; + uint8_t provider_name[256]; - int pcr_pid; -- int pcr_packet_count; -- int pcr_packet_period; + int64_t pcr, pcr_packet_timer, pcr_packet_period; + int pcr_sid, pcr_pid; AVProgram *program; } MpegTSService; -@@ -78,14 +77,12 @@ +@@ -76,11 +77,12 @@ typedef struct MpegTSWrite { MpegTSSection pat; /* MPEG-2 PAT table */ MpegTSSection sdt; /* MPEG-2 SDT table context */ MpegTSService **services; -- int sdt_packet_count; -- int sdt_packet_period; -- int pat_packet_count; -- int pat_packet_period; +- 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; - int onid; - int tsid; - 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; -@@ -95,12 +92,14 @@ +@@ -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 reemit_pat_pmt; // backward compatibility - -- int pcr_period; +- 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 -@@ -111,8 +110,6 @@ +@@ -106,10 +108,8 @@ typedef struct MpegTSWrite { + int flags; + int copyts; int tables_version; - double pat_period; - double sdt_period; +- 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; -@@ -222,10 +219,10 @@ +@@ -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 "Service01" +-#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) */ @@ -68,17 +77,290 @@ diff -urN a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c +#define PCR_RETRANS_TIME 50 typedef struct MpegTSWriteStream { - struct MpegTSService *service; -@@ -721,6 +718,7 @@ - service->pmt.pid = ts->pmt_start_pid + ts->nb_services; - service->sid = sid; - service->pcr_pid = 0x1fff; -+ service->pcr_sid = 0x1fff; - service->provider_name = av_strdup(provider_name); - service->name = av_strdup(name); - if (!service->provider_name || !service->name) -@@ -736,18 +734,11 @@ - return NULL; ++ 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 last_pcr; ++ AVRational user_tb; + + /* 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: + return 0; } -static int64_t get_pcr(const MpegTSWrite *ts, AVIOContext *pb) @@ -87,42 +369,230 @@ diff -urN a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c - ts->first_pcr; -} - - static void mpegts_prefix_m2ts_header(AVFormatContext *s) - { - MpegTSWrite *ts = s->priv_data; - if (ts->m2ts_mode) { +-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; -+ 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)); -@@ -768,6 +759,7 @@ +- 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; - AVStream *st, *pcr_st = NULL; - AVDictionaryEntry *title, *provider; +- 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; + } + +-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; -@@ -776,6 +768,15 @@ ++ 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; ++ 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; -+ } else { -+ ts->m2ts_mode = 0; -+ } -+ } + 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; -@@ -822,6 +823,8 @@ - service->program = program; + ++ 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) @@ -130,78 +600,181 @@ diff -urN a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c ts->pat.pid = PAT_PID; /* Initialize at 15 so that it wraps and is equal to 0 for the -@@ -907,10 +910,9 @@ +@@ -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) { +- 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->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_pid == 0x1fff) { -- service->pcr_pid = ts_st->pid; ++ /* update PCR pid by using the first video stream */ ++ if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && + service->pcr_sid == 0x1fff) - pcr_st = st; -- } ++ pcr_st = st; + if (st->codecpar->codec_id == AV_CODEC_ID_AAC && st->codecpar->extradata_size > 0) { AVStream *ast; -@@ -946,78 +948,47 @@ - av_freep(&pids); - - /* if no video stream, use the first stream as PCR */ -- if (service->pcr_pid == 0x1fff && s->nb_streams > 0) { -- pcr_st = s->streams[0]; -- ts_st = pcr_st->priv_data; -- service->pcr_pid = ts_st->pid; -- } else -- ts_st = pcr_st->priv_data; -- -- if (ts->mux_rate > 1) { -- service->pcr_packet_period = (int64_t)ts->mux_rate * ts->pcr_period / -- (TS_PACKET_SIZE * 8 * 1000); -- ts->sdt_packet_period = (int64_t)ts->mux_rate * SDT_RETRANS_TIME / -- (TS_PACKET_SIZE * 8 * 1000); -- ts->pat_packet_period = (int64_t)ts->mux_rate * PAT_RETRANS_TIME / -- (TS_PACKET_SIZE * 8 * 1000); -- -- if (ts->copyts < 1) -- ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, AV_TIME_BASE); -- } else { -- /* Arbitrary values, PAT/PMT will also be written on video key frames */ -- ts->sdt_packet_period = 200; -- ts->pat_packet_period = 40; -- 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"); -- service->pcr_packet_period = -- pcr_st->codecpar->sample_rate / (10 * 512); -- } else { -- service->pcr_packet_period = -- pcr_st->codecpar->sample_rate / (10 * frame_size); -- } -- } else { -- // max delta PCR 0.1s -- // TODO: should be avg_frame_rate -- service->pcr_packet_period = -- ts_st->user_tb.den / (10 * ts_st->user_tb.num); -- } -- if (!service->pcr_packet_period) -- service->pcr_packet_period = 1; -- } -- -- ts->last_pat_ts = AV_NOPTS_VALUE; -- ts->last_sdt_ts = AV_NOPTS_VALUE; -- // The user specified a period, use only it -- if (ts->pat_period < INT_MAX/2) { -- ts->pat_packet_period = INT_MAX; + 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; - } -- if (ts->sdt_period < INT_MAX/2) { -- ts->sdt_packet_period = INT_MAX; ++ } + ts_st = pcr_st->priv_data; + if (service->pcr_sid == 0x1fff) + service->pcr_sid = ts_st->pid; @@ -212,8 +785,8 @@ diff -urN a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c + 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; @@ -223,13 +796,16 @@ diff -urN a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c + 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); -+ - // output a PCR as soon as possible -- service->pcr_packet_count = service->pcr_packet_period; -- ts->pat_packet_count = ts->pat_packet_period - 1; -- ts->sdt_packet_count = ts->sdt_packet_period - 1; + 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; @@ -240,48 +816,55 @@ diff -urN a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c else av_log(s, AV_LOG_VERBOSE, "muxrate %d, ", ts->mux_rate); - av_log(s, AV_LOG_VERBOSE, -- "pcr every %d pkts, sdt every %d, pat/pmt every %d pkts\n", -- service->pcr_packet_period, -- ts->sdt_packet_period, ts->pat_packet_period); -- -- if (ts->m2ts_mode == -1) { -- if (av_match_ext(s->url, "m2ts")) { -- ts->m2ts_mode = 1; -- } else { -- ts->m2ts_mode = 0; -- } -- } +- "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; + } -@@ -1032,22 +1003,12 @@ + /* 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 (++ts->sdt_packet_count == ts->sdt_packet_period || -- (dts != AV_NOPTS_VALUE && ts->last_sdt_ts == AV_NOPTS_VALUE) || -- (dts != AV_NOPTS_VALUE && dts - ts->last_sdt_ts >= ts->sdt_period*90000.0) +- 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 - ) { -- ts->sdt_packet_count = 0; -- if (dts != AV_NOPTS_VALUE) -- ts->last_sdt_ts = FFMAX(dts, ts->last_sdt_ts); +- 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 (++ts->pat_packet_count == ts->pat_packet_period || -- (dts != AV_NOPTS_VALUE && ts->last_pat_ts == AV_NOPTS_VALUE) || -- (dts != AV_NOPTS_VALUE && dts - ts->last_pat_ts >= ts->pat_period*90000.0) || +- 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) { -- ts->pat_packet_count = 0; -- if (dts != AV_NOPTS_VALUE) -- ts->last_pat_ts = FFMAX(dts, ts->last_pat_ts); +- 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]); -@@ -1089,13 +1050,14 @@ +@@ -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); + } + + /* 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) { MpegTSWrite *ts = s->priv_data; MpegTSWriteStream *ts_st = st->priv_data; @@ -298,7 +881,7 @@ diff -urN a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c *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 */ -@@ -1106,7 +1068,7 @@ +@@ -1200,11 +1076,12 @@ static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st) } /* PCR coded into 6 bytes */ @@ -307,64 +890,114 @@ diff -urN a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c /* stuffing bytes */ memset(q, 0xFF, TS_PACKET_SIZE - (q - buf)); -@@ -1175,8 +1137,6 @@ +- 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; int afc_len, stuffing_len; -- int64_t pcr = -1; /* avoid warning */ - 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); -@@ -1186,28 +1146,33 @@ + 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, dts); + +- 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_st->pid == ts_st->service->pcr_pid) { -- if (ts->mux_rate > 1 || is_start) // VBR pcr period is based on frames -- ts_st->service->pcr_packet_count++; -- if (ts_st->service->pcr_packet_count >= -- ts_st->service->pcr_packet_period) { -- ts_st->service->pcr_packet_count = 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 - get_pcr(ts, s->pb) / 300) > delay) { -- /* pcr insert gets priority over null packet insert */ -- if (write_pcr) -- mpegts_insert_pcr_only(s, st); ++ 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 retransmit si_info */ ++ else + mpegts_insert_null_packet(s); + /* recalculate write_pcr and possibly retransimit si_info */ - continue; - } ++ continue; ++ } -@@ -1217,6 +1182,10 @@ + /* 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 && @@ -374,25 +1007,22 @@ diff -urN a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c *q++ = val; *q++ = ts_st->pid; ts_st->cc = ts_st->cc + 1 & 0xf; -@@ -1228,7 +1197,7 @@ +@@ -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->pid == ts_st->service->pcr_pid) +- 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); -@@ -1236,14 +1205,10 @@ +@@ -1365,10 +1213,10 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, 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 (ts->mux_rate > 1) -- pcr = get_pcr(ts, s->pb); -- else -- pcr = (dts - delay) * 300; - 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)); @@ -400,7 +1030,22 @@ diff -urN a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c q = get_ts_payload_start(buf); } if (is_start) { -@@ -1344,11 +1309,13 @@ +@@ -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) { @@ -416,24 +1061,64 @@ diff -urN a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c q += 5; } if (pes_extension && st->codecpar->codec_id == AV_CODEC_ID_DIRAC) { -@@ -1519,7 +1486,6 @@ +@@ -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) 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; -@@ -1540,16 +1506,15 @@ - } +@@ -1657,11 +1506,23 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt) + if (side_data) + stream_id = side_data[0]; - if (ts->flags & MPEGTS_FLAG_REEMIT_PAT_PMT) { -- ts->pat_packet_count = ts->pat_packet_period - 1; -- ts->sdt_packet_count = ts->sdt_packet_period - 1; ++ 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; - } - ++ ts->flags &= ~MPEGTS_FLAG_REEMIT_PAT_PMT; ++ } ++ if (ts->copyts < 1) { if (pts != AV_NOPTS_VALUE) - pts += delay; @@ -444,54 +1129,207 @@ diff -urN a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c } if (ts_st->first_pts_check && pts == AV_NOPTS_VALUE) { -@@ -1737,7 +1702,7 @@ - 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 > delay/2)) { +@@ -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) + } + } + ++ 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); -@@ -1908,12 +1873,18 @@ ++ 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" }, { "mpegts_pmt_start_pid", "Set the first pid of the PMT.", - offsetof(MpegTSWrite, pmt_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 }, ++ 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.", - 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, 1, AV_OPT_FLAG_ENCODING_PARAM }, +- 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 }, -@@ -1951,15 +1922,15 @@ ++ { "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", - offsetof(MpegTSWrite, omit_video_pes_length), AV_OPT_TYPE_BOOL, - { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, +- OFFSET(omit_video_pes_length), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, ENC }, - { "pcr_period", "PCR retransmission time in milliseconds", -- offsetof(MpegTSWrite, pcr_period), AV_OPT_TYPE_INT, -- { .i64 = PCR_RETRANS_TIME }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, +- 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 = INT_MAX }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, -- { "sdt_period", "SDT retransmission time limit in seconds", ++ 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 = INT_MAX }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, ++ offsetof(MpegTSWrite, sdt_period), AV_OPT_TYPE_DOUBLE, + { .dbl = SDT_RETRANS_TIME }, -1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, { NULL }, };