Browse code

avformat/mpegtsenc: Add option to mark stream begin as discontinuous

This avoids continuity check failures in concatenated streams

Reviewed-by: Steven Liu <lingjiujianke@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>

Michael Niedermayer authored on 2016/11/02 08:51:52
Showing 2 changed files
... ...
@@ -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,