Hi, I am attaching another, hopefully cleaner, version of the Random Access indicator patch for mpeg-ts muxer.
Random Access indicator can be used to mark keyframes, and is required by some DVB recorders to be able to index and replay the recorded stream. -- Jindrich Makovicka
From 7c6a9d0618e045af2026218aff92b400e7b8ee0f Mon Sep 17 00:00:00 2001 From: Jindrich Makovicka <[email protected]> Date: Tue, 21 Jun 2011 18:50:58 +0200 Subject: [PATCH] set Random Access indicator on keyframe start packets --- libavformat/mpegtsenc.c | 67 +++++++++++++++++++++++++++++++++++++++------- 1 files changed, 56 insertions(+), 11 deletions(-) diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c index 26d2cb2..e75bce0 100644 --- a/libavformat/mpegtsenc.c +++ b/libavformat/mpegtsenc.c @@ -203,6 +203,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; @@ -620,7 +621,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; @@ -631,7 +632,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 */ @@ -667,7 +668,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)); @@ -688,6 +689,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. @@ -695,7 +729,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; @@ -740,8 +774,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); @@ -749,9 +792,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; @@ -949,20 +991,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); @@ -987,7 +1031,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); } -- 1.7.5.4
_______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
