|
|
|
@ -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); |
|
|
|
|
} |
|
|
|
|