From patchwork Fri Jul 21 20:37:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Devin Heitmueller X-Patchwork-Id: 42893 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:be1d:b0:130:ccc6:6c4b with SMTP id ge29csp479118pzb; Fri, 21 Jul 2023 13:38:42 -0700 (PDT) X-Google-Smtp-Source: APBJJlHL6n2PPbmOkOMRkOakst7gEhtde4S9B392nARok7mYLBVnZ8cdT+iSphFnsJSu1aRinbU6 X-Received: by 2002:a17:906:1bb1:b0:988:71c8:9f3a with SMTP id r17-20020a1709061bb100b0098871c89f3amr2975696ejg.16.1689971921858; Fri, 21 Jul 2023 13:38:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689971921; cv=none; d=google.com; s=arc-20160816; b=SNAAXTn/Dqz48gSyzN+XUfU9l/ahRmITmD+A+uKfr+lug384fqZL8Tm03flTCWmKM6 J4pl/ZFOiY99DxVQ7pVapGmjbWMrG2aQVWuU99MC4+zTLQ4Y6WZ1Vw1EwIV7qhbKTlcD SvcAaY6e4bkFkEAOy8P0SSwnrTQ3spxTpXyfpvbq4IXT/0JaCzHB5sfybKbEyqK4C1l8 Eqfdz9+NoFy7+cYvE2YY5oUmIz8AGCGqg0EUg5EzKV83sCbbzEwg83rSVNu89U5pnZIU GW5RD5IxIfNp5oYRIAmJfFauQ99ZGVio0IKHeIepWsn0YZhmnMd1TF2OskrD9k7nuq3d EwMw== 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=hJwOVyZjdURcDdsBKi7PcKkMKCZAjejav8sjMZ2wF9TtdXBY+RX2Lqp07xDLlwsZlM dcDMRY710brND1L0qCHN8fPC8JgQDl22sn8uOijT7uf5qGs/+ff3Gi8mJi5zhsQi3N/2 w1nh7if4S2gqIEVECeFq+pvySaYpFMEeV5ad5P80yBwaO8iEwnkogqqsQvLBZx0QEUUQ W/o6tl+cVaP13fy/Y3q3KsgI1rbjVOgjwCWR7TfoHexOZ5h9dJInRsAZjuqj8D39M9vm 8vYs5uVNK0oLpWEe0L5YrD9+tJZhVXTBoB5nbfRt6ZAHumadOkbg4eptn6vknnhEpGLh nkYw== 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=AFy+bKur; 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 i18-20020a17090639d200b0099367e9043dsi2720849eje.870.2023.07.21.13.38.41; Fri, 21 Jul 2023 13:38:41 -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=AFy+bKur; 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 95BB868C65B; Fri, 21 Jul 2023 23:38:12 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-vk1-f182.google.com (mail-vk1-f182.google.com [209.85.221.182]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1985B68C5E6 for ; Fri, 21 Jul 2023 23:38:05 +0300 (EEST) Received: by mail-vk1-f182.google.com with SMTP id 71dfb90a1353d-483e175352cso839449e0c.2 for ; Fri, 21 Jul 2023 13:38:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ltnglobal-com.20221208.gappssmtp.com; s=20221208; t=1689971883; x=1690576683; 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=AFy+bKurELGR3WsAmKqNjR0gUpBI3wPHggcfCvIMNx/fJuH4bxA5lHRwLWNAQlVkal xDwTadkpXppfchxa4BYGfxo+ommaRb3sQWaujtjtBbQP6yXqHPX1wcK5E+3COgMzrQFJ YRjjFP3T+jzSmxZ+l9VgRN2493aBRgM+IQQEEN36dX8MzCePAM0bu1WOGMFtU4WP+h5k Himrjk4nKePGQ8RCJDPt6SNUvW8w0pA1NozleXMaOq3FMjr6IyjkZJBnr4EI9FDNuf8s Ij2ZkHiwr2WOlzURpkd7YrF9qTbqkcJc3ROcUla7mnqzcTown4DlUzDP/Dw8T1hb6h2p 0ALw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1689971883; x=1690576683; 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=ZdCY5qvIOPIJv4z8twuexoqEw5RZmLNTH+N1aZIBxw1bgdZElTxsYJmNE4qndujIes KGhGLmE4Qz0mw6CnC5Z5AsU0fTmaqJ7G6eXQy50411ZOrQQYqx8ush7Yw19VPD+b8fda ojyeITIWeoaj+6r63Jf2cHHPAP6Q37nPEX+hYUVOifEZNJfYiE96g4LPI+HHoUinMtL7 yA9KWy1qV68bi5iRSPrdidCcpRBSbZz4F/XPP6SF6QBLdIM9Q9eg4lf2Rkaua3kZOz55 V4jnRF3W+Rbxh9kjQQ8ZEVP+KInjbfqd0tCKa+5xV9upWW4LDzHS5cNhuMu/DN+pJqQ8 GV0A== X-Gm-Message-State: ABy/qLb9R+AzNj/ZBeoMw9x04reeDytlOlg8G9uWO+XeBzWrNMwdeMd+ tOoXXeduyndB9R/CdOFarhCLOx6FLHZX4HepB1M= X-Received: by 2002:a05:6102:14d:b0:443:6352:4650 with SMTP id a13-20020a056102014d00b0044363524650mr668991vsr.7.1689971882736; Fri, 21 Jul 2023 13:38:02 -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 i16-20020a0cf390000000b0063646f1147asm1534077qvk.135.2023.07.21.13.38.02 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 21 Jul 2023 13:38:02 -0700 (PDT) From: Devin Heitmueller X-Google-Original-From: Devin Heitmueller To: ffmpeg-devel@ffmpeg.org Date: Fri, 21 Jul 2023 16:37:57 -0400 Message-Id: <1689971878-26226-4-git-send-email-dheitmueller@ltnglobal.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1689971878-26226-1-git-send-email-dheitmueller@ltnglobal.com> References: <1689971878-26226-1-git-send-email-dheitmueller@ltnglobal.com> Subject: [FFmpeg-devel] [PATCH v3 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: 2GnkPsqASPWN 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; } }