This avoids continuity check failures in concatenated streams
Reviewed-by: Steven Liu <lingjiujianke@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
... | ... |
@@ -1055,6 +1055,8 @@ Use LATM packetization for AAC. |
1055 | 1055 |
Reemit PAT and PMT at each video frame. |
1056 | 1056 |
@item system_b |
1057 | 1057 |
Conform to System B (DVB) instead of System A (ATSC). |
1058 |
+@item initial_discontinuity |
|
1059 |
+Mark the initial packet of each stream as discontinuity. |
|
1058 | 1060 |
@end table |
1059 | 1061 |
|
1060 | 1062 |
@subsection Example |
... | ... |
@@ -46,6 +46,7 @@ |
46 | 46 |
typedef struct MpegTSSection { |
47 | 47 |
int pid; |
48 | 48 |
int cc; |
49 |
+ int discontinuity; |
|
49 | 50 |
void (*write_packet)(struct MpegTSSection *s, const uint8_t *packet); |
50 | 51 |
void *opaque; |
51 | 52 |
} MpegTSSection; |
... | ... |
@@ -104,6 +105,7 @@ typedef struct MpegTSWrite { |
104 | 104 |
#define MPEGTS_FLAG_AAC_LATM 0x02 |
105 | 105 |
#define MPEGTS_FLAG_PAT_PMT_AT_FRAMES 0x04 |
106 | 106 |
#define MPEGTS_FLAG_SYSTEM_B 0x08 |
107 |
+#define MPEGTS_FLAG_DISCONT 0x10 |
|
107 | 108 |
int flags; |
108 | 109 |
int copyts; |
109 | 110 |
int tables_version; |
... | ... |
@@ -153,6 +155,12 @@ static void mpegts_write_section(MpegTSSection *s, uint8_t *buf, int len) |
153 | 153 |
*q++ = s->pid; |
154 | 154 |
s->cc = s->cc + 1 & 0xf; |
155 | 155 |
*q++ = 0x10 | s->cc; |
156 |
+ if (s->discontinuity) { |
|
157 |
+ q[-1] |= 0x20; |
|
158 |
+ *q++ = 1; |
|
159 |
+ *q++ = 0x80; |
|
160 |
+ s->discontinuity = 0; |
|
161 |
+ } |
|
156 | 162 |
if (first) |
157 | 163 |
*q++ = 0; /* 0 offset */ |
158 | 164 |
len1 = TS_PACKET_SIZE - (q - packet); |
... | ... |
@@ -223,6 +231,7 @@ typedef struct MpegTSWriteStream { |
223 | 223 |
struct MpegTSService *service; |
224 | 224 |
int pid; /* stream associated pid */ |
225 | 225 |
int cc; |
226 |
+ int discontinuity; |
|
226 | 227 |
int payload_size; |
227 | 228 |
int first_pts_check; ///< first pts check needed |
228 | 229 |
int prev_payload_key; |
... | ... |
@@ -782,6 +791,7 @@ static int mpegts_init(AVFormatContext *s) |
782 | 782 |
service->pmt.write_packet = section_write_packet; |
783 | 783 |
service->pmt.opaque = s; |
784 | 784 |
service->pmt.cc = 15; |
785 |
+ service->pmt.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT; |
|
785 | 786 |
} else { |
786 | 787 |
for (i = 0; i < s->nb_programs; i++) { |
787 | 788 |
AVProgram *program = s->programs[i]; |
... | ... |
@@ -800,6 +810,7 @@ static int mpegts_init(AVFormatContext *s) |
800 | 800 |
service->pmt.write_packet = section_write_packet; |
801 | 801 |
service->pmt.opaque = s; |
802 | 802 |
service->pmt.cc = 15; |
803 |
+ service->pmt.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT; |
|
803 | 804 |
service->program = program; |
804 | 805 |
} |
805 | 806 |
} |
... | ... |
@@ -808,11 +819,13 @@ static int mpegts_init(AVFormatContext *s) |
808 | 808 |
/* Initialize at 15 so that it wraps and is equal to 0 for the |
809 | 809 |
* first packet we write. */ |
810 | 810 |
ts->pat.cc = 15; |
811 |
+ ts->pat.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT; |
|
811 | 812 |
ts->pat.write_packet = section_write_packet; |
812 | 813 |
ts->pat.opaque = s; |
813 | 814 |
|
814 | 815 |
ts->sdt.pid = SDT_PID; |
815 | 816 |
ts->sdt.cc = 15; |
817 |
+ ts->sdt.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT; |
|
816 | 818 |
ts->sdt.write_packet = section_write_packet; |
817 | 819 |
ts->sdt.opaque = s; |
818 | 820 |
|
... | ... |
@@ -883,6 +896,7 @@ static int mpegts_init(AVFormatContext *s) |
883 | 883 |
ts_st->payload_dts = AV_NOPTS_VALUE; |
884 | 884 |
ts_st->first_pts_check = 1; |
885 | 885 |
ts_st->cc = 15; |
886 |
+ ts_st->discontinuity = ts->flags & MPEGTS_FLAG_DISCONT; |
|
886 | 887 |
/* update PCR pid by using the first video stream */ |
887 | 888 |
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && |
888 | 889 |
service->pcr_pid == 0x1fff) { |
... | ... |
@@ -1078,6 +1092,10 @@ static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st) |
1078 | 1078 |
/* Continuity Count field does not increment (see 13818-1 section 2.4.3.3) */ |
1079 | 1079 |
*q++ = TS_PACKET_SIZE - 5; /* Adaptation Field Length */ |
1080 | 1080 |
*q++ = 0x10; /* Adaptation flags: PCR present */ |
1081 |
+ if (ts_st->discontinuity) { |
|
1082 |
+ q[-1] |= 0x80; |
|
1083 |
+ ts_st->discontinuity = 0; |
|
1084 |
+ } |
|
1081 | 1085 |
|
1082 | 1086 |
/* PCR coded into 6 bytes */ |
1083 | 1087 |
q += write_pcr_bits(q, get_pcr(ts, s->pb)); |
... | ... |
@@ -1195,6 +1213,11 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, |
1195 | 1195 |
*q++ = ts_st->pid; |
1196 | 1196 |
ts_st->cc = ts_st->cc + 1 & 0xf; |
1197 | 1197 |
*q++ = 0x10 | ts_st->cc; // payload indicator + CC |
1198 |
+ if (ts_st->discontinuity) { |
|
1199 |
+ set_af_flag(buf, 0x80); |
|
1200 |
+ q = get_ts_payload_start(buf); |
|
1201 |
+ ts_st->discontinuity = 0; |
|
1202 |
+ } |
|
1198 | 1203 |
if (key && is_start && pts != AV_NOPTS_VALUE) { |
1199 | 1204 |
// set Random Access for key frames |
1200 | 1205 |
if (ts_st->pid == ts_st->service->pcr_pid) |
... | ... |
@@ -1872,6 +1895,9 @@ static const AVOption options[] = { |
1872 | 1872 |
{ "system_b", "Conform to System B (DVB) instead of System A (ATSC)", |
1873 | 1873 |
0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_SYSTEM_B }, 0, INT_MAX, |
1874 | 1874 |
AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" }, |
1875 |
+ { "initial_discontinuity", "Mark initial packets as discontinuous", |
|
1876 |
+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_DISCONT }, 0, INT_MAX, |
|
1877 |
+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" }, |
|
1875 | 1878 |
// backward compatibility |
1876 | 1879 |
{ "resend_headers", "Reemit PAT/PMT before writing the next packet", |
1877 | 1880 |
offsetof(MpegTSWrite, reemit_pat_pmt), AV_OPT_TYPE_INT, |