From: Devin Heitmueller <devin.heitmueller@ltnglobal.com> To: ffmpeg-devel@ffmpeg.org Cc: Devin Heitmueller <dheitmueller@ltnglobal.com> Subject: [FFmpeg-devel] [PATCH v3 3/4] mpegtsenc: Add support for output of SCTE-35 streams over TS Date: Fri, 21 Jul 2023 16:37:57 -0400 Message-ID: <1689971878-26226-4-git-send-email-dheitmueller@ltnglobal.com> (raw) In-Reply-To: <1689971878-26226-1-git-send-email-dheitmueller@ltnglobal.com> Introduce the ability to pass through SCTE-35 packets when creating MPEG transport streams. Note that this patch makes no effort to change the PTS values in the SCTE-35 packets, and thus only works when not reclocking the stream (i.e. using -copyts). A subsequent patch includes a BSF to recompute the PTS values. Signed-off-by: Devin Heitmueller <dheitmueller@ltnglobal.com> --- libavformat/mpegts.h | 1 + libavformat/mpegtsenc.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++--- libavformat/mux.c | 6 ++-- 3 files changed, 75 insertions(+), 6 deletions(-) diff --git a/libavformat/mpegts.h b/libavformat/mpegts.h index a48f14e..a7aaaba 100644 --- a/libavformat/mpegts.h +++ b/libavformat/mpegts.h @@ -137,6 +137,7 @@ #define STREAM_TYPE_AUDIO_AC3 0x81 #define STREAM_TYPE_AUDIO_DTS 0x82 #define STREAM_TYPE_AUDIO_TRUEHD 0x83 +#define STREAM_TYPE_SCTE_35 0x86 #define STREAM_TYPE_AUDIO_EAC3 0x87 /* ISO/IEC 13818-1 Table 2-22 */ diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c index 700fc54..c6cd1fd 100644 --- a/libavformat/mpegtsenc.c +++ b/libavformat/mpegtsenc.c @@ -425,6 +425,9 @@ static int get_dvb_stream_type(AVFormatContext *s, AVStream *st) case AV_CODEC_ID_SMPTE_2038: stream_type = STREAM_TYPE_PRIVATE_DATA; break; + case AV_CODEC_ID_SCTE_35: + stream_type = STREAM_TYPE_SCTE_35; + break; case AV_CODEC_ID_DVB_SUBTITLE: case AV_CODEC_ID_DVB_TELETEXT: case AV_CODEC_ID_ARIB_CAPTION: @@ -522,6 +525,16 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) *q++ = 0xfc; // private_data_byte } + /* If there is an SCTE-35 stream, we need a registration descriptor + at the program level (SCTE 35 2016 Sec 8.1) */ + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + if (st->codecpar->codec_id == AV_CODEC_ID_SCTE_35) { + put_registration_descriptor(&q, MKTAG('C', 'U', 'E', 'I')); + break; + } + } + val = 0xf000 | (q - program_info_length_ptr - 2); program_info_length_ptr[0] = val >> 8; program_info_length_ptr[1] = val; @@ -533,6 +546,14 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) const char default_language[] = "und"; const char *language = lang && strlen(lang->value) >= 3 ? lang->value : default_language; enum AVCodecID codec_id = st->codecpar->codec_id; + uint16_t pid; + + if (st->codecpar->codec_id == AV_CODEC_ID_SCTE_35) { + MpegTSSection *sect = st->priv_data; + pid = sect->pid; + } else { + pid = ts_st->pid; + } if (s->nb_programs) { int k, found = 0; @@ -556,7 +577,7 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) stream_type = ts->m2ts_mode ? get_m2ts_stream_type(s, st) : get_dvb_stream_type(s, st); *q++ = stream_type; - put16(&q, 0xe000 | ts_st->pid); + put16(&q, 0xe000 | pid); desc_length_ptr = q; q += 2; /* patched after */ @@ -819,6 +840,10 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) putbuf(&q, tag, strlen(tag)); *q++ = 0; /* metadata service ID */ *q++ = 0xF; /* metadata_locator_record_flag|MPEG_carriage_flags|reserved */ + } else if (st->codecpar->codec_id == AV_CODEC_ID_SCTE_35) { + *q++ = 0x8a; /* Cue Identifier Descriptor */ + *q++ = 0x01; /* length */ + *q++ = 0x01; /* Cue Stream Type (see Sec 8.2) */ } break; } @@ -1159,6 +1184,33 @@ static int mpegts_init(AVFormatContext *s) AVStream *st = s->streams[i]; MpegTSWriteStream *ts_st; + if (st->codecpar->codec_id == AV_CODEC_ID_SCTE_35) { + struct MpegTSSection *sect; + sect = av_mallocz(sizeof(MpegTSSection)); + if (!sect) { + ret = AVERROR(ENOMEM); + continue; + } + + if (st->id < 16) { + sect->pid = ts->start_pid + i; + } else if (st->id < 0x1FFF) { + sect->pid = st->id; + } else { + av_log(s, AV_LOG_ERROR, + "Invalid stream id %d, must be less than 8191\n", st->id); + ret = AVERROR(EINVAL); + continue; + } + + sect->write_packet = section_write_packet; + sect->opaque = s; + sect->cc = 15; + sect->discontinuity= ts->flags & MPEGTS_FLAG_DISCONT; + st->priv_data = sect; + continue; + } + ts_st = av_mallocz(sizeof(MpegTSWriteStream)); if (!ts_st) { return AVERROR(ENOMEM); @@ -1877,6 +1929,19 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt) dts += delay; } + if (st->codecpar->codec_id == AV_CODEC_ID_SCTE_35) { + MpegTSSection *s = st->priv_data; + uint8_t data[SECTION_LENGTH]; + + if (size > SECTION_LENGTH) { + av_log(s, AV_LOG_ERROR, "SCTE-35 section too long\n"); + return AVERROR_INVALIDDATA; + } + memcpy(data, buf, size); + mpegts_write_section(s, data, size); + return 0; + } + if (!ts_st->first_timestamp_checked && (pts == AV_NOPTS_VALUE || dts == AV_NOPTS_VALUE)) { av_log(s, AV_LOG_ERROR, "first pts and dts value must be set\n"); return AVERROR_INVALIDDATA; @@ -2149,7 +2214,8 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt) return 0; } - if (ts_st->payload_size && (ts_st->payload_size + size > ts->pes_payload_size || + if (st->codecpar->codec_id != AV_CODEC_ID_SCTE_35 && + ts_st->payload_size && (ts_st->payload_size + size > ts->pes_payload_size || (dts != AV_NOPTS_VALUE && ts_st->payload_dts != AV_NOPTS_VALUE && dts - ts_st->payload_dts >= max_audio_delay) || ts_st->opus_queued_samples + opus_samples >= 5760 /* 120ms */)) { @@ -2194,7 +2260,7 @@ static void mpegts_write_flush(AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; MpegTSWriteStream *ts_st = st->priv_data; - if (ts_st->payload_size > 0) { + if (st->codecpar->codec_id != AV_CODEC_ID_SCTE_35 && ts_st->payload_size > 0) { mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_size, ts_st->payload_pts, ts_st->payload_dts, ts_st->payload_flags & AV_PKT_FLAG_KEY, -1); @@ -2237,7 +2303,7 @@ static void mpegts_deinit(AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; MpegTSWriteStream *ts_st = st->priv_data; - if (ts_st) { + if (ts_st && st->codecpar->codec_id != AV_CODEC_ID_SCTE_35) { av_freep(&ts_st->dvb_ac3_desc); av_freep(&ts_st->payload); if (ts_st->amux) { diff --git a/libavformat/mux.c b/libavformat/mux.c index 415bd39..55bec25 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -307,7 +307,8 @@ FF_ENABLE_DEPRECATION_WARNINGS } if (par->codec_type != AVMEDIA_TYPE_ATTACHMENT && - par->codec_id != AV_CODEC_ID_SMPTE_2038) + par->codec_id != AV_CODEC_ID_SMPTE_2038 && + par->codec_id != AV_CODEC_ID_SCTE_35) si->nb_interleaved_streams++; } si->interleave_packet = of->interleave_packet; @@ -946,7 +947,8 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *pkt, } else if (par->codec_type != AVMEDIA_TYPE_ATTACHMENT && par->codec_id != AV_CODEC_ID_VP8 && par->codec_id != AV_CODEC_ID_VP9 && - par->codec_id != AV_CODEC_ID_SMPTE_2038) { + par->codec_id != AV_CODEC_ID_SMPTE_2038 && + par->codec_id != AV_CODEC_ID_SCTE_35) { ++noninterleaved_count; } } -- 1.8.3.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2023-07-21 20:38 UTC|newest] Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top 2023-07-21 20:37 [FFmpeg-devel] [PATCH v3 0/4] Add passthrough support for SCTE-35 Devin Heitmueller 2023-07-21 20:37 ` [FFmpeg-devel] [PATCH v3 1/4] avcodec: Add new side data type to contain original PTS value Devin Heitmueller 2023-07-21 20:37 ` [FFmpeg-devel] [PATCH v3 2/4] mpegts: Stash original PTS for SCTE-35 sections for processing later Devin Heitmueller 2023-07-21 20:37 ` Devin Heitmueller [this message] 2023-07-21 20:37 ` [FFmpeg-devel] [PATCH v3 4/4] bsf: Add new bitstream filter to set SCTE-35 pts_adjustment when reclocking Devin Heitmueller 2023-07-27 15:33 ` James Almer 2023-07-27 15:08 ` [FFmpeg-devel] [PATCH v3 0/4] Add passthrough support for SCTE-35 Devin Heitmueller
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1689971878-26226-4-git-send-email-dheitmueller@ltnglobal.com \ --to=devin.heitmueller@ltnglobal.com \ --cc=dheitmueller@ltnglobal.com \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git