From patchwork Fri Jun 16 22:12:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Devin Heitmueller X-Patchwork-Id: 42159 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:c526:b0:117:ac03:c9de with SMTP id gm38csp1831645pzb; Fri, 16 Jun 2023 14:15:43 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4vRLoUcy/2W/iX0yqLdDMOhQjAZZzPpJ9mKXj/l8dTWE4Qvhvt+EIhWxf41uOK96GKLL1H X-Received: by 2002:a17:907:1b17:b0:96f:1f79:c0a6 with SMTP id mp23-20020a1709071b1700b0096f1f79c0a6mr2677434ejc.70.1686950143072; Fri, 16 Jun 2023 14:15:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1686950143; cv=none; d=google.com; s=arc-20160816; b=ojwU14fyR2vNY4v6Lz0Xn0I058UkA/6dDzWDbDSg3nAI5vwpDpJNtNU2Ynlertpzfs p5iQt0VtTQ1bOcv3uTqsHb8fGWwF3xHjkytFzODdMqGOnI/lNZ5NSOPG5faNyzAkVmx4 ymxU3HfC4A3aKW+sLvKjUudrHrT7MWtRZTha8rBHeHUpvgW82eHD512u0mYlixzXHAx5 REg6tR+H54AT5SPqljDw2IkkbYlDMFFh6sUnrnlq0MSp4U5m4gwDI5yek1iGLTh2n6an 7aN7rw1pK8EmghPZVbWFjVSbcq16NxXNQ8cB4ExODAWNZNkU9xMuQkmP8MpXV0VaCwHI iorA== 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=; b=At93PcE2NnX3nAXlkUFWaP8+z4I2kKrVNxD/WNSK/6Bd0a9ah9b0MhFylOyFsv6P29 4xgxW30kvC69UL7UtiqUZYIUCtTGF2cYOzODFlTDHS6Oq1l6uMJv/NqvfFNV/hy1BOfY m6v36SChQ65FLJU6HLUmJfVD+S1xQve9aCEN0HJ/EvM5NUU/lkfdLMN+Om+BRoyAcajZ zqyVrMGbEjgkgHUlHNjkWAamgcTDgbD+KNwN+d+nPxTnOazefVhRaAOU43IAs1lmqf0h FsVdyVPa8knv9WvbckjqCBt3FwmF87ETp6chk6F/N+QOMBEbIJJceAmlOiSsJpmR+DTV r5Vg== 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="1lR/kxth"; 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 i23-20020a170906251700b00982c69d8103si2040252ejb.797.2023.06.16.14.15.39; Fri, 16 Jun 2023 14:15:43 -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="1lR/kxth"; 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 20F2E68C297; Sat, 17 Jun 2023 00:15:11 +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 CCE9A68BD68 for ; Sat, 17 Jun 2023 00:15:02 +0300 (EEST) Received: by mail-qk1-f177.google.com with SMTP id af79cd13be357-7622f7903edso96725885a.0 for ; Fri, 16 Jun 2023 14:15:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ltnglobal-com.20221208.gappssmtp.com; s=20221208; t=1686950101; x=1689542101; 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=1lR/kxth7zScPOqOzALWY21Ro45x9EQGPIdo73ulWS8yR5dd49kyXJWqvReBRkZ7d/ zt60wzuz31jZIQbVpBO7ChUhLli6PQ1rWhoHlWhgoiBLM1gZ1mcYcqcWs+Q+QgZ3oPIz 9gX5mAZl9tZiY+huQ1k8zlB1X/vfC/JqBBFLRLwq7qPPXC7FmuoP/8BnOT0u5jqM0ize Vv3FZ4hyTm1l6KBQ77tiZjQBdDmQz5xEIPQL523pws1/1wlM2RvDYdWB29sZ9cmIQ7y9 5RndyXG+b0Y/HuhmTjRC6qGBGesC9s09Jg5PP+AJlU3QjJewCQlxzrx24L6CemHIz3m8 I0zA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686950101; x=1689542101; 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=CYtlOJo62pZ0Iq4wpQfCQAG8akt9zaARjRJpNqRxrxWC7XEyz6ZGxA6VA70VHb/4rd GTe8xdhW4Vx0v2r+W+rXcEn319zLRxXWEgNlOm0YEZk/RDPvXJdH3n2OUaR4rL0bovYO 0Egx8BouOsaoJYhOa/rvNja5O50JI4Utu3eTSfa6r6U4viyJ2dfOfmfj29Usnvl68Irp SJMlv8QyVw0ojvFVGLUMYrJE0bM0qbpdRKqs3B53nB4oOhKGiTZgyEtj+W3S2NOVKgnM TqzEyesALynDkKPvlUjLUTudIuOjM+Bl7aYpC1O/Z/QFQ5B/mFNkasXCXOIy9aRQUEfl +aMg== X-Gm-Message-State: AC+VfDxN/198LTMU798TpG/iH7Dhh4MLL7fuBEE3L/fMVGn8KfegB+tb Br2UV7g0Ud8JkTPjFiljS4icbJpNogHBD86QPfs= X-Received: by 2002:a05:6214:21c1:b0:62d:e3c1:b884 with SMTP id d1-20020a05621421c100b0062de3c1b884mr3830207qvh.16.1686950100975; Fri, 16 Jun 2023 14:15:00 -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 t8-20020a0cb388000000b0061a68b5a8c4sm7450812qve.134.2023.06.16.14.15.00 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 16 Jun 2023 14:15:00 -0700 (PDT) From: Devin Heitmueller X-Google-Original-From: Devin Heitmueller To: ffmpeg-devel@ffmpeg.org Date: Fri, 16 Jun 2023 18:12:56 -0400 Message-Id: <1686953578-18843-4-git-send-email-dheitmueller@ltnglobal.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1686953578-18843-1-git-send-email-dheitmueller@ltnglobal.com> References: <1686953578-18843-1-git-send-email-dheitmueller@ltnglobal.com> Subject: [FFmpeg-devel] [PATCH 3/5] 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: +uAqtZb/4MnM 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; } }