typedef struct MpegTSSection {
int pid;
int cc;
+ int discontinuity;
void (*write_packet)(struct MpegTSSection *s, const uint8_t *packet);
void *opaque;
} MpegTSSection;
#define MPEGTS_FLAG_AAC_LATM 0x02
#define MPEGTS_FLAG_PAT_PMT_AT_FRAMES 0x04
#define MPEGTS_FLAG_SYSTEM_B 0x08
+#define MPEGTS_FLAG_DISCONT 0x10
int flags;
int copyts;
int tables_version;
*q++ = s->pid;
s->cc = s->cc + 1 & 0xf;
*q++ = 0x10 | s->cc;
+ if (s->discontinuity) {
+ q[-1] |= 0x20;
+ *q++ = 1;
+ *q++ = 0x80;
+ s->discontinuity = 0;
+ }
if (first)
*q++ = 0; /* 0 offset */
len1 = TS_PACKET_SIZE - (q - packet);
struct MpegTSService *service;
int pid; /* stream associated pid */
int cc;
+ int discontinuity;
int payload_size;
int first_pts_check; ///< first pts check needed
int prev_payload_key;
data, q - data);
}
+/* NOTE: !str is accepted for an empty string */
+static void putstr8(uint8_t **q_ptr, const char *str, int write_len)
+{
+ uint8_t *q;
+ int len;
+
+ q = *q_ptr;
+ if (!str)
+ len = 0;
+ else
+ len = strlen(str);
+ if (write_len)
+ *q++ = len;
+ memcpy(q, str, len);
+ q += len;
+ *q_ptr = q;
+}
+
static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
{
MpegTSWrite *ts = s->priv_data;
*q++ = 'V';
*q++ = 'A';
} else if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
- *q++ = 0x5; /* MPEG-2 registration descriptor */
- *q++ = 4;
- *q++ = 'I';
- *q++ = 'D';
- *q++ = '3';
- *q++ = ' ';
+ const char *tag = "ID3 ";
+ *q++ = 0x26; /* metadata descriptor */
+ *q++ = 13;
+ put16(&q, 0xffff); /* metadata application format */
+ putstr8(&q, tag, 0);
+ *q++ = 0xff; /* metadata format */
+ putstr8(&q, tag, 0);
+ *q++ = 0; /* metadata service ID */
+ *q++ = 0xF; /* metadata_locator_record_flag|MPEG_carriage_flags|reserved */
}
break;
}
return 0;
}
-/* NOTE: !str is accepted for an empty string */
-static void putstr8(uint8_t **q_ptr, const char *str)
-{
- uint8_t *q;
- int len;
-
- q = *q_ptr;
- if (!str)
- len = 0;
- else
- len = strlen(str);
- *q++ = len;
- memcpy(q, str, len);
- q += len;
- *q_ptr = q;
-}
-
static void mpegts_write_sdt(AVFormatContext *s)
{
MpegTSWrite *ts = s->priv_data;
desc_len_ptr = q;
q++;
*q++ = ts->service_type;
- putstr8(&q, service->provider_name);
- putstr8(&q, service->name);
+ putstr8(&q, service->provider_name, 1);
+ putstr8(&q, service->name, 1);
desc_len_ptr[0] = q - desc_len_ptr - 1;
/* fill descriptor length */
service->pmt.write_packet = section_write_packet;
service->pmt.opaque = s;
service->pmt.cc = 15;
+ service->pmt.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT;
} else {
for (i = 0; i < s->nb_programs; i++) {
AVProgram *program = s->programs[i];
service->pmt.write_packet = section_write_packet;
service->pmt.opaque = s;
service->pmt.cc = 15;
+ service->pmt.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT;
service->program = program;
}
}
/* Initialize at 15 so that it wraps and is equal to 0 for the
* first packet we write. */
ts->pat.cc = 15;
+ ts->pat.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT;
ts->pat.write_packet = section_write_packet;
ts->pat.opaque = s;
ts->sdt.pid = SDT_PID;
ts->sdt.cc = 15;
+ ts->sdt.discontinuity= ts->flags & MPEGTS_FLAG_DISCONT;
ts->sdt.write_packet = section_write_packet;
ts->sdt.opaque = s;
ts_st->payload_dts = AV_NOPTS_VALUE;
ts_st->first_pts_check = 1;
ts_st->cc = 15;
+ ts_st->discontinuity = ts->flags & MPEGTS_FLAG_DISCONT;
/* update PCR pid by using the first video stream */
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
service->pcr_pid == 0x1fff) {
/* Continuity Count field does not increment (see 13818-1 section 2.4.3.3) */
*q++ = TS_PACKET_SIZE - 5; /* Adaptation Field Length */
*q++ = 0x10; /* Adaptation flags: PCR present */
+ if (ts_st->discontinuity) {
+ q[-1] |= 0x80;
+ ts_st->discontinuity = 0;
+ }
/* PCR coded into 6 bytes */
q += write_pcr_bits(q, get_pcr(ts, s->pb));
*q++ = ts_st->pid;
ts_st->cc = ts_st->cc + 1 & 0xf;
*q++ = 0x10 | ts_st->cc; // payload indicator + CC
+ if (ts_st->discontinuity) {
+ set_af_flag(buf, 0x80);
+ q = get_ts_payload_start(buf);
+ ts_st->discontinuity = 0;
+ }
if (key && is_start && pts != AV_NOPTS_VALUE) {
// set Random Access for key frames
if (ts_st->pid == ts_st->service->pcr_pid)
if (st->codecpar->codec_id == AV_CODEC_ID_H264) {
if (pkt->size >= 5 && AV_RB32(pkt->data) != 0x0000001 &&
- AV_RB24(pkt->data) != 0x000001)
+ (AV_RB24(pkt->data) != 0x000001 ||
+ (st->codecpar->extradata_size > 0 &&
+ st->codecpar->extradata[0] == 1)))
ret = ff_stream_add_bitstream_filter(st, "h264_mp4toannexb", NULL);
} else if (st->codecpar->codec_id == AV_CODEC_ID_HEVC) {
if (pkt->size >= 5 && AV_RB32(pkt->data) != 0x0000001 &&
- AV_RB24(pkt->data) != 0x000001)
+ (AV_RB24(pkt->data) != 0x000001 ||
+ (st->codecpar->extradata_size > 0 &&
+ st->codecpar->extradata[0] == 1)))
ret = ff_stream_add_bitstream_filter(st, "hevc_mp4toannexb", NULL);
}
{ .i64 = 0x1000 }, 0x0010, 0x1f00, AV_OPT_FLAG_ENCODING_PARAM },
{ "mpegts_start_pid", "Set the first pid.",
offsetof(MpegTSWrite, start_pid), AV_OPT_TYPE_INT,
- { .i64 = 0x0100 }, 0x0020, 0x0f00, AV_OPT_FLAG_ENCODING_PARAM },
+ { .i64 = 0x0100 }, 0x0010, 0x0f00, AV_OPT_FLAG_ENCODING_PARAM },
{ "mpegts_m2ts_mode", "Enable m2ts mode.",
offsetof(MpegTSWrite, m2ts_mode), AV_OPT_TYPE_BOOL,
{ .i64 = -1 }, -1, 1, AV_OPT_FLAG_ENCODING_PARAM },
{ "system_b", "Conform to System B (DVB) instead of System A (ATSC)",
0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_SYSTEM_B }, 0, INT_MAX,
AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" },
+ { "initial_discontinuity", "Mark initial packets as discontinuous",
+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_FLAG_DISCONT }, 0, INT_MAX,
+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" },
// backward compatibility
{ "resend_headers", "Reemit PAT/PMT before writing the next packet",
offsetof(MpegTSWrite, reemit_pat_pmt), AV_OPT_TYPE_INT,