From patchwork Mon Jul 31 13:38:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Devin Heitmueller X-Patchwork-Id: 43051 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:ba09:b0:130:ccc6:6c4b with SMTP id fa9csp119680pzb; Mon, 31 Jul 2023 06:38:50 -0700 (PDT) X-Google-Smtp-Source: APBJJlHr+MO5KnymWOEoXNgS2snpq5chhkIqPy70D8sWRDfFSZeKHPMPmSltBtIGRqTatpopTu6m X-Received: by 2002:a17:906:77d5:b0:993:d617:bdc5 with SMTP id m21-20020a17090677d500b00993d617bdc5mr6310114ejn.37.1690810730458; Mon, 31 Jul 2023 06:38:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690810730; cv=none; d=google.com; s=arc-20160816; b=OuRFuPyGWDkd9MgzAff9IaYEgxKzx83cQMUEZtUCkVSwYIbWJEwd27Y7XSjVR9iXvc E7fvM+H2gYNi9BJKzaiwN8j2ymalrQ2EpE24lEvAYAddkGIoRdiLamWTvniLorAN/mMT RimZBHFejYWQSb41l76MxdkVLqrAuf6IB6FNZhH4W3IqfAGwxZmOJfjoWKWxzoc6QCfI 8JX5HewaHzxl8uUxUPrvp2eIfyqBwIBGpFbxIxMoQ3ooPsiKYbJwu4KQwXAO4V9lT46T 9hmGeIMkK+pQvbxRNJmR5KnWLIEBgrKrpvlIWHcIGNgcc6mEEx7ViR8JWZJNHCbuO57h 4hIA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to; bh=avgFnl6HNAVzdvvAjCF+yXZAt4n/dTgq+Y6281Jhzsw=; fh=DKzdJpyueDOox6ShoNYUi750QZs6R2naOS9+hcsrM90=; b=Xk8mDwmjlwBrM+SFMTiPy/RjwZLwGfvNiy8kl7O4ICAVBiAG3KYLip7ZxMVHYzxgFn F9HPpayzcW5gk8KTBQKT14DSibF9V1dgN+pEWp95UshlplzmbmGZ8KEdzWtnL8CWHzpt aPeAjaR9q+o7DM/WZZjAeQkMPABABA3U88ioq5a5NmWF1r8aREDvFrTOs/kdhkmuntt3 UEfZ+uGK8gQG1N8eNIzHPICN5QnZOHqn9kSI3aQyKa0oEe/2Gsi9UtvAW43eE4ImZSMs H0EtOLBxx8D6FQN80Pt0pFY11Pv4cdTxWfe0cL1RTSAsPPIXSm0SwtReXzNr4GtLmTeX 8foA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@ltnglobal-com.20221208.gappssmtp.com header.s=20221208 header.b=NrrnCS6b; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id f9-20020a170906138900b009828e8bec17si7171082ejc.531.2023.07.31.06.38.50; Mon, 31 Jul 2023 06:38:50 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@ltnglobal-com.20221208.gappssmtp.com header.s=20221208 header.b=NrrnCS6b; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 0992C68C36E; Mon, 31 Jul 2023 16:38:24 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qk1-f177.google.com (mail-qk1-f177.google.com [209.85.222.177]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 4426A68BFF8 for ; Mon, 31 Jul 2023 16:38:15 +0300 (EEST) Received: by mail-qk1-f177.google.com with SMTP id af79cd13be357-765a7768f1dso411567885a.0 for ; Mon, 31 Jul 2023 06:38:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ltnglobal-com.20221208.gappssmtp.com; s=20221208; t=1690810693; x=1691415493; h=references:in-reply-to:message-id:date:subject:cc:to:from:from:to :cc:subject:date:message-id:reply-to; bh=mgn1IXm5zp+Oc2RiyejXeVRTpXXr4BQSkba+CMTiD5g=; b=NrrnCS6bKEeg6xbEr+aeZhM/pKNWw8wcCh0yncxwoAs48541hPa90Ox+OTgQ6CMdOl hfbD+s1XKIkGxjpH0MyrSj+qG8nl2XoCsmGUYKihCaC5COTSuIUK7KFYzXCgdDmN/YNk 6UUEPEigxfF1Cgj5TLRa4qE3EPGktwg4BBiMRl8nbKQT2i4vkuiUXfUrkIHiLfComN6w IwNHkuckPW24k39tIZ62rLxvwBBbUXz0JbZd1d1yrlSWFibCapZ+v22YCKs74zCy1+jZ T6797DpMM7nnKf+g1LZ3OQ6nUy0ETZfadUbO3w0lwE52l0G9Z+ruH75HyhKyGPcNJEAB xuMw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1690810693; x=1691415493; h=references:in-reply-to:message-id:date:subject:cc:to:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=mgn1IXm5zp+Oc2RiyejXeVRTpXXr4BQSkba+CMTiD5g=; b=BWIcgZ6y0aBCV4FTE0Yz9PjSyqkv62D6bqu7bsteo7B7MjZukoh3WeEKQsGmIaf/JT CtQkdevYrK9dc5WFibxuRMVULl3T3Da1BjRWdJcudbPy1VXm4N4Vv/gMZ70mDKL/NdXa a4t8lIN06+huTIWL9VHl6n0oKyjluSGNPXGCAMnVz242hwnNYjySFOGDmlEhkicnb20z QBo55FHbAzVDK91FiLNoQ5TkE9GtIssHlHdVjyJdyNG6hF7zClG1MoG9/x0afnudjdnG 3Dk+886q6Eg7098wmJIE/grm+TOjZvGswzG5a19gDxpVAl8bwuCr4B45o5D3J60EjlSb jBmQ== X-Gm-Message-State: ABy/qLZaZXDzZ2DzyCmE2f5I5cMc6Q+JK+2SI28me4aXj8HNi4pv/I1b Z9tvipT5JYql14UewWJsTObH39WFrTygG1k2zvQ= X-Received: by 2002:a05:620a:2551:b0:765:8063:c369 with SMTP id s17-20020a05620a255100b007658063c369mr12144136qko.74.1690810693581; Mon, 31 Jul 2023 06:38:13 -0700 (PDT) Received: from ltnt-nyc-580testdevin.livetimenet.com (pool-71-105-132-214.nycmny.fios.verizon.net. [71.105.132.214]) by smtp.gmail.com with ESMTPSA id o9-20020a05620a110900b0076c84240467sm2504235qkk.52.2023.07.31.06.38.12 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 31 Jul 2023 06:38:12 -0700 (PDT) From: Devin Heitmueller X-Google-Original-From: Devin Heitmueller To: ffmpeg-devel@ffmpeg.org Date: Mon, 31 Jul 2023 09:38:05 -0400 Message-Id: <1690810686-4723-4-git-send-email-dheitmueller@ltnglobal.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1690810686-4723-1-git-send-email-dheitmueller@ltnglobal.com> References: <1690810686-4723-1-git-send-email-dheitmueller@ltnglobal.com> Subject: [FFmpeg-devel] [PATCH v4 3/4] mpegtsenc: Add support for output of SCTE-35 streams over TS X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Devin Heitmueller MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 7j2Pq2r4/pwT 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 --- 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; } }