From patchwork Mon Jul 3 18:15:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Devin Heitmueller X-Patchwork-Id: 42398 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:3b1e:b0:12b:9ae3:586d with SMTP id c30csp4516693pzh; Mon, 3 Jul 2023 10:18:05 -0700 (PDT) X-Google-Smtp-Source: APBJJlFS31Pl8+dqTkQ7SWQi2TsbfXJh4kRayL7C6KqN7mvp7BxBJiefrFcT3/GRfTV7bYeVDYZw X-Received: by 2002:a2e:968d:0:b0:2b6:dd85:1206 with SMTP id q13-20020a2e968d000000b002b6dd851206mr4209711lji.49.1688404685341; Mon, 03 Jul 2023 10:18:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1688404685; cv=none; d=google.com; s=arc-20160816; b=Xp7yAjOfbabhxkwElGWn9PiwEYKUYBqHcJZDn5Xb1+L6e/xNEe25r8D9x54XiIoTmR hfJktZvSctUhL/SOoxo91dSytRqhx6lqUSs6XzbC0fetX14Jzs64ZtRjapn/SQs5EwcP Wl7GT440waU68XagHD9aSdJfBtaxJ1aEtYjID3KYBf5Bi1HFoGK54+OVcyrIMfwNQnYZ L1wBV6bpjWSH23Vy8sKa02NReFRFA6W6pvwvVDdUjjow8o91jyo3UrqfDZmA3CxDPfKP hi42R1b1JaOPQ2XedmaBNb2ZdYwN2qm25BUVy5/59fcIWOmbWc4XHMbNO1KqH1LvQeTa 1AjQ== 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=pXLAZvRiz3/uELcsWNfKAkJPgyV9/rr3Mrznj9KeXEo=; b=tUQkNLDtzEjlmPo3sMbdKdE8JuNylbqPj8gj5SFXPN6OcBzM6KU/AYBw7rfjOnh3dn wZFIsez3vgZzB7HCQiHvYc+Kn3KZOxMzMcJPk55/RoiOc+UPmIWdrVT54RO/OY8EuHK+ 0mG7t5eT2c8m+HHk7DCA2l3srdYX6jWk3MwimElGpoynmD5rsHpXSEtAa0OHrD3m5DBI OBm6RTJd2YoU3OKDQOJT5ziARB3iSHFbMVTBh4p+2/C/SUPU1/xjqMoyN8yVg/Sg5Wc1 6B3VLF6itSJFNi2qfDUkNpkhP5fjxsK74VhmFR5P+8QzeoAHc3ORaWR8Yvt6SdqUjTiv 7l8A== 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=y5Jq6jew; 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 b24-20020a1709062b5800b0099363826e3fsi1870807ejg.177.2023.07.03.10.18.04; Mon, 03 Jul 2023 10:18:05 -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=y5Jq6jew; 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 2A1BC68C58C; Mon, 3 Jul 2023 20:17:32 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qt1-f175.google.com (mail-qt1-f175.google.com [209.85.160.175]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 5352F68C56D for ; Mon, 3 Jul 2023 20:17:22 +0300 (EEST) Received: by mail-qt1-f175.google.com with SMTP id d75a77b69052e-400a39d4ffcso20667831cf.0 for ; Mon, 03 Jul 2023 10:17:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ltnglobal-com.20221208.gappssmtp.com; s=20221208; t=1688404641; x=1690996641; 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=y5Jq6jewm4MBucqhEvgfSZZEg1Fn0TYTKMGBy2FcU5+ZXxRkb14qrnvIC3xY5mlc3G wDDR/X6DSBA68exCLyAdWwiC8f/8SVRn84fRyKQYAIeYShM1SJxM4yd/vUmWICI/YiGU 3Y17gSDcVYSDRwYqpf7JsBBWLkb+f0/QYXg8sWarShdZN73LOZjZuzwLz8usseo3vCan zbKV3Wt4zzrSAYbLoZjy9J9jYImtPHnjWjn/BbMIQX0TAHAxyGW20TUTG+kcndsACtf1 /JU4TF67tjTii7HXj+DyXMOFIwJowoYz4+6A9Sr+SXHOWruykVo15yukHR8i0VyToNr7 kHEA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1688404641; x=1690996641; 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=eNp5ZJ3TC5m6vnX+PCnGu/VMk3SGO9lDoBFlQ3GlS2vp51dTA46N2z1ACKP1FNY9v3 twK8z43Rcs+4oPjx2uJMhMFyiHgcVs7YOroG5FSrZ/kowQQClAqzYHNAWSrT8uDuXeNG vs+gnSf0qVQVStvFofH/6xl5fPXYIsmUPrMm66S5krRvqfkSTzflvZQNW2/rqcNS5Fhl 28VQwzmu6VZ2weFGwz7ycUMaeVvoyO7Z29iTGqCyMr7fgpiDDmw6RAlZ++AazrVfUL1N bX17Y2jX0ECuX3tG5bSvXafXxFPkeNIFei55sF+/+dS5ySWT1EDZU4jHxdTalUzx8BxL ow5w== X-Gm-Message-State: AC+VfDw53uQsg8EoVhpgchQisrTMA291Dejz+dXpTkb/6qq7UFE5M1an x7QIUuAcec4fyLLOuNWOywaNLeUgNL+bGK6pbXA= X-Received: by 2002:a05:622a:1750:b0:3f8:6a2f:c47a with SMTP id l16-20020a05622a175000b003f86a2fc47amr13061330qtk.21.1688404640866; Mon, 03 Jul 2023 10:17:20 -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 m20-20020ac85b14000000b003f6c9f8f0a8sm8730193qtw.68.2023.07.03.10.17.20 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 03 Jul 2023 10:17:20 -0700 (PDT) From: Devin Heitmueller X-Google-Original-From: Devin Heitmueller To: ffmpeg-devel@ffmpeg.org Date: Mon, 3 Jul 2023 14:15:07 -0400 Message-Id: <1688408109-14381-4-git-send-email-dheitmueller@ltnglobal.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1688408109-14381-1-git-send-email-dheitmueller@ltnglobal.com> References: <1688408109-14381-1-git-send-email-dheitmueller@ltnglobal.com> Subject: [FFmpeg-devel] [PATCH v2 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: Y2QDrU9ZINF3 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; } }