mpegtsenc: set Random Access indicator on keyframe start packets
authorJindrich Makovicka <jindrich.makovicka@nangu.tv>
Wed, 29 Jun 2011 13:01:39 +0000 (15:01 +0200)
committerAnton Khirnov <anton@khirnov.net>
Wed, 13 Jul 2011 18:49:26 +0000 (20:49 +0200)
Signed-off-by: Jindrich Makovicka <jindrich.makovicka@nangu.tv>
Signed-off-by: Anton Khirnov <anton@khirnov.net>
libavformat/mpegtsenc.c
tests/ref/lavf/ts

index 83ede1d..72ff289 100644 (file)
@@ -204,6 +204,7 @@ typedef struct MpegTSWriteStream {
     int first_pts_check; ///< first pts check needed
     int64_t payload_pts;
     int64_t payload_dts;
+    int payload_flags;
     uint8_t payload[DEFAULT_PES_PAYLOAD_SIZE];
     ADTSContext *adts;
 } MpegTSWriteStream;
@@ -621,7 +622,7 @@ static int64_t get_pcr(const MpegTSWrite *ts, AVIOContext *pb)
            ts->first_pcr;
 }
 
-static uint8_t* write_pcr_bits(uint8_t *buf, int64_t pcr)
+static int write_pcr_bits(uint8_t *buf, int64_t pcr)
 {
     int64_t pcr_low = pcr % 300, pcr_high = pcr / 300;
 
@@ -632,7 +633,7 @@ static uint8_t* write_pcr_bits(uint8_t *buf, int64_t pcr)
     *buf++ = pcr_high << 7 | pcr_low >> 8 | 0x7e;
     *buf++ = pcr_low;
 
-    return buf;
+    return 6;
 }
 
 /* Write a single null transport stream packet */
@@ -668,7 +669,7 @@ static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st)
     *q++ = 0x10;               /* Adaptation flags: PCR present */
 
     /* PCR coded into 6 bytes */
-    q = write_pcr_bits(q, get_pcr(ts, s->pb));
+    q += write_pcr_bits(q, get_pcr(ts, s->pb));
 
     /* stuffing bytes */
     memset(q, 0xFF, TS_PACKET_SIZE - (q - buf));
@@ -689,6 +690,39 @@ static void write_pts(uint8_t *q, int fourbits, int64_t pts)
     *q++ = val;
 }
 
+/* Set an adaptation field flag in an MPEG-TS packet*/
+static void set_af_flag(uint8_t *pkt, int flag)
+{
+    // expect at least one flag to set
+    assert(flag);
+
+    if ((pkt[3] & 0x20) == 0) {
+        // no AF yet, set adaptation field flag
+        pkt[3] |= 0x20;
+        // 1 byte length, no flags
+        pkt[4] = 1;
+        pkt[5] = 0;
+    }
+    pkt[5] |= flag;
+}
+
+/* Extend the adaptation field by size bytes */
+static void extend_af(uint8_t *pkt, int size)
+{
+    // expect already existing adaptation field
+    assert(pkt[3] & 0x20);
+    pkt[4] += size;
+}
+
+/* Get a pointer to MPEG-TS payload (right after TS packet header) */
+static uint8_t *get_ts_payload_start(uint8_t *pkt)
+{
+    if (pkt[3] & 0x20)
+        return pkt + 5 + pkt[4];
+    else
+        return pkt + 4;
+}
+
 /* Add a pes header to the front of payload, and segment into an integer number of
  * ts packets. The final ts packet is padded using an over-sized adaptation header
  * to exactly fill the last ts packet.
@@ -696,7 +730,7 @@ static void write_pts(uint8_t *q, int fourbits, int64_t pts)
  */
 static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
                              const uint8_t *payload, int payload_size,
-                             int64_t pts, int64_t dts)
+                             int64_t pts, int64_t dts, int key)
 {
     MpegTSWriteStream *ts_st = st->priv_data;
     MpegTSWrite *ts = s->priv_data;
@@ -741,8 +775,17 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
         *q++ = val;
         *q++ = ts_st->pid;
         ts_st->cc = (ts_st->cc + 1) & 0xf;
-        *q++ = 0x10 | ts_st->cc | (write_pcr ? 0x20 : 0);
+        *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)
+                write_pcr = 1;
+            set_af_flag(buf, 0x40);
+            q = get_ts_payload_start(buf);
+        }
         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);
@@ -750,9 +793,8 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
                 pcr = (dts - delay)*300;
             if (dts != AV_NOPTS_VALUE && dts < pcr / 300)
                 av_log(s, AV_LOG_WARNING, "dts < pcr, TS is invalid\n");
-            *q++ = 7; /* AFC length */
-            *q++ = 0x10; /* flags: PCR present */
-            q = write_pcr_bits(q, pcr);
+            extend_af(buf, write_pcr_bits(q, pcr));
+            q = get_ts_payload_start(buf);
         }
         if (is_start) {
             int pes_extension = 0;
@@ -950,20 +992,22 @@ static int mpegts_write_packet(AVFormatContext *s, AVPacket *pkt)
 
     if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
         // for video and subtitle, write a single pes packet
-        mpegts_write_pes(s, st, buf, size, pts, dts);
+        mpegts_write_pes(s, st, buf, size, pts, dts, pkt->flags & AV_PKT_FLAG_KEY);
         av_free(data);
         return 0;
     }
 
     if (ts_st->payload_index + size > DEFAULT_PES_PAYLOAD_SIZE) {
         mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_index,
-                         ts_st->payload_pts, ts_st->payload_dts);
+                         ts_st->payload_pts, ts_st->payload_dts,
+                         ts_st->payload_flags & AV_PKT_FLAG_KEY);
         ts_st->payload_index = 0;
     }
 
     if (!ts_st->payload_index) {
         ts_st->payload_pts = pts;
         ts_st->payload_dts = dts;
+        ts_st->payload_flags = pkt->flags;
     }
 
     memcpy(ts_st->payload + ts_st->payload_index, buf, size);
@@ -988,7 +1032,8 @@ static int mpegts_write_end(AVFormatContext *s)
         ts_st = st->priv_data;
         if (ts_st->payload_index > 0) {
             mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_index,
-                             ts_st->payload_pts, ts_st->payload_dts);
+                             ts_st->payload_pts, ts_st->payload_dts,
+                             ts_st->payload_flags & AV_PKT_FLAG_KEY);
         }
         av_freep(&ts_st->adts);
     }
index 989f8fb..325112c 100644 (file)
@@ -1,3 +1,3 @@
-d260ac0534ff2e26b44b5192fd4fdc21 *./tests/data/lavf/lavf.ts
+9708011dd80212a0041a96da878122c2 *./tests/data/lavf/lavf.ts
 406644 ./tests/data/lavf/lavf.ts
 ./tests/data/lavf/lavf.ts CRC=0x133216c1