--- a/libavformat/mpegtsenc.c 2016-09-30 19:12:42.000000000 -0600 +++ b/libavformat/mpegtsenc.c 2017-01-25 17:25:58.720017593 -0700 @@ -55,7 +55,7 @@ int sid; /* service ID */ char *name; char *provider_name; - int pcr_pid; + int pcr_sid, pcr_pid; int pcr_packet_count; int pcr_packet_period; AVProgram *program; @@ -94,8 +94,10 @@ int service_type; int pmt_start_pid; + int pcr_start_pid; int start_pid; int m2ts_mode; + int64_t pcr_offset; int reemit_pat_pmt; // backward compatibility @@ -704,6 +706,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) @@ -722,7 +725,7 @@ 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; + ts->first_pcr + ts->pcr_offset; } static void mpegts_prefix_m2ts_header(AVFormatContext *s) @@ -760,6 +763,14 @@ if (s->max_delay < 0) /* Not set by the caller */ s->max_delay = 0; + if (ts->m2ts_mode == -1) { + if (av_match_ext(s->filename, "m2ts")) { + ts->m2ts_mode = 1; + } else { + ts->m2ts_mode = 0; + } + } + // round up to a whole number of TS packets ts->pes_payload_size = (ts->pes_payload_size + 14 + 183) / 184 * 184 - 14; @@ -803,6 +814,8 @@ 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 @@ -885,10 +898,9 @@ ts_st->cc = 15; /* 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; + service->pcr_sid == 0x1fff) pcr_st = st; - } + if (st->codecpar->codec_id == AV_CODEC_ID_AAC && st->codecpar->extradata_size > 0) { AVStream *ast; @@ -924,12 +936,24 @@ 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 (!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; + } if (ts->mux_rate > 1) { service->pcr_packet_period = (int64_t)ts->mux_rate * ts->pcr_period / @@ -989,14 +1013,6 @@ service->pcr_packet_period, ts->sdt_packet_period, ts->pat_packet_period); - if (ts->m2ts_mode == -1) { - if (av_match_ext(s->filename, "m2ts")) { - ts->m2ts_mode = 1; - } else { - ts->m2ts_mode = 0; - } - } - return 0; fail: @@ -1010,9 +1026,9 @@ MpegTSWrite *ts = s->priv_data; int i; - if (++ts->sdt_packet_count == ts->sdt_packet_period || + if ( ts->sdt_period >= 0 && (++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) + (dts != AV_NOPTS_VALUE && dts - ts->last_sdt_ts >= ts->sdt_period*90000.0)) ) { ts->sdt_packet_count = 0; if (dts != AV_NOPTS_VALUE) @@ -1067,13 +1083,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 */ @@ -1148,7 +1165,7 @@ uint8_t buf[TS_PACKET_SIZE]; uint8_t *q; int val, is_start, len, header_len, write_pcr, is_dvb_subtitle, is_dvb_teletext, flags; - int afc_len, stuffing_len; + int afc_len, stuffing_len, write_null; 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; @@ -1163,8 +1180,8 @@ retransmit_si_info(s, force_pat, dts); force_pat = 0; - write_pcr = 0; - if (ts_st->pid == ts_st->service->pcr_pid) { + write_pcr = write_null = 0; + if (ts_st->pid == ts_st->service->pcr_sid) { 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 >= @@ -1173,15 +1190,17 @@ write_pcr = 1; } } - 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); - else - mpegts_insert_null_packet(s); - /* recalculate write_pcr and possibly retransmit si_info */ + (dts - get_pcr(ts, s->pb) / 300) > delay) { + write_null = 1; + } + /* pcr insert gets priority over null packet insert */ + if (write_pcr && ts_st->service->pcr_sid != ts_st->service->pcr_pid) { + mpegts_insert_pcr_only(s, st); + continue; + } + if (write_null) { + mpegts_insert_null_packet(s); continue; } @@ -1191,13 +1210,17 @@ val = ts_st->pid >> 8; 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; *q++ = 0x10 | ts_st->cc; // payload indicator + CC 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->pid == ts_st->service->pcr_sid) write_pcr = 1; set_af_flag(buf, 0x40); q = get_ts_payload_start(buf); @@ -1310,11 +1333,13 @@ *q++ = flags; *q++ = header_len; if (pts != AV_NOPTS_VALUE) { - write_pts(q, flags >> 6, pts); + int64_t ts_pts = pts + ts->pcr_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->pcr_offset; + write_pts(q, 1, ts_dts); q += 5; } if (pes_extension && st->codecpar->codec_id == AV_CODEC_ID_DIRAC) { @@ -1838,12 +1863,18 @@ { "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 }, + { "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 }, 0x0020, 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 }, + { .i64 = -1 }, -1, 2, AV_OPT_FLAG_ENCODING_PARAM }, + { "mpegts_pcr_offset", "clock offset.", + offsetof(MpegTSWrite, pcr_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 }, @@ -1886,7 +1917,7 @@ { .dbl = INT_MAX }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, { "sdt_period", "SDT retransmission time limit in seconds", offsetof(MpegTSWrite, sdt_period), AV_OPT_TYPE_DOUBLE, - { .dbl = INT_MAX }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, + { .dbl = INT_MAX }, -1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, { NULL }, };