From patchwork Mon Jun 24 08:49:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Martin_Storsj=C3=B6?= X-Patchwork-Id: 50118 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:ae71:0:b0:482:c625:d099 with SMTP id w17csp1867619vqz; Mon, 24 Jun 2024 01:50:31 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCWwmIaVnRhg2YWa6162f88I8y9aTu3SABEJQmEH55VEHMl566/OeOvvFE726ywhYxkqh/uJLo9CymOXxZABNJRq5EkaB3QfbW6xiA== X-Google-Smtp-Source: AGHT+IFRYaptrLLqaituOP/+931aXLHYeFhlAoPS2eWJcaNevSgU7cS3S2XLmg4CHDvaqXNe2K6P X-Received: by 2002:ac2:5f4c:0:b0:52c:d9c6:68c8 with SMTP id 2adb3069b0e04-52ce0646938mr3178036e87.65.1719219031344; Mon, 24 Jun 2024 01:50:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1719219031; cv=none; d=google.com; s=arc-20160816; b=YtQBavqAUwho9gNXnxhEHzEkpxIvssFb4RImAYyKXw4y2OhLFq4lAS8gAVFRYia5kK mG9Jk3vsEIxom+mM9ZwSXOPkIMaRCIZv1z+K0z/3jb2lGytVgMdZcALVHCPHgtwRdgN8 faIn4WhKNrI4JUk6l760VYNnRRhzbZukohzDjOVFGTuTPuHT682Ni7yufVCeFqr6+FQJ 1t22a2yxVpCpAlculkBOJsflRpQDTA/3QxTBe0gXc8FTggB5t1xIxkbEMddZ1tbgIpWv XpgGcLit4bl8jxc2TqfsR3N9fSGJ/ne8cLTHfBUWreXnLj1cBMwxA9rnJIOiA5qUK+qx Yt8g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=AyZCcVXAVlrrkwuHiqMHp0zy+8l80oUWVqlrBJ50+Tg=; fh=UvIsH30fhBXMmPtaePKJMeMspabJNvEuvy3Hi3mTDRo=; b=CN6cwDK2BNdGonnCJCqW01KbgQp72D1g9Le8l2PLpltdCKsSPudtEvXIlVumtcx9Sy E0thFoxBRGcVM5io+zp9Jj2kWt6UQsHRF/YtOwq2OIva11NRUWsDlt/OzHjW2jZQ9QiK gMv4TjyOl24FwcUaNIFVlAuCgZ5UU03EWwqgCYg1ROlar4o5jmCX7auxpTJ4p0rnF6aF oMrfEqkIEbL2FtgRIsybxEt+FtN5358KErpFJJE2rpucH1zIerwIiDGhRgpivMAsS3GQ 6dVix3EVX0UY6UfRVXC7b/EVtlVr6OTXt58aUce4J7eZt8aSr9dptjhTLGS57EPujMA5 Y8jQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@martin-st.20230601.gappssmtp.com header.s=20230601 header.b=rHA8zoa2; 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 2adb3069b0e04-52cd63bca03si2069330e87.155.2024.06.24.01.50.30; Mon, 24 Jun 2024 01:50:31 -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=@martin-st.20230601.gappssmtp.com header.s=20230601 header.b=rHA8zoa2; 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 D065A68D631; Mon, 24 Jun 2024 11:49:56 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lj1-f169.google.com (mail-lj1-f169.google.com [209.85.208.169]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 6EF8168D607 for ; Mon, 24 Jun 2024 11:49:47 +0300 (EEST) Received: by mail-lj1-f169.google.com with SMTP id 38308e7fff4ca-2ebed33cb65so44889671fa.2 for ; Mon, 24 Jun 2024 01:49:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=martin-st.20230601.gappssmtp.com; s=20230601; t=1719218986; x=1719823786; darn=ffmpeg.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ovBNJqtaentgVtQEXlyPygZISuo2WWXb8Qyqt0eVvkk=; b=rHA8zoa2DwIwehlYTzwpiPW9F9tcesly7koySopakW6cmtf7/A84QQp/pQt1R/L9Ib FkGXo3Uq9h93Tqg9Yv6btUr/U2N6TY8/nIwxY12VUD9S6plByIdjy/3+OAMZYJ7lpI9L vwvGr3tL9mBeNgmusc50MEKHyx9Ca1kCkGmWHY6aiZzMx00Y6UPUVoJVUnbUGQ4Slosc 81lnnpBrXkJ+1TsJMB3hnVeC+//EyrImjBxfOT3gHn6Zy9wkCaJ/FOMtgpmR9qhC2Ee4 nmldJ0WTa7XIb+5zc6q5ummrRY/p9IL4PGvY/aWyyWDkEeRouJ091xUtgKap3GOtR//5 vzRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1719218986; x=1719823786; h=content-transfer-encoding:mime-version: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=ovBNJqtaentgVtQEXlyPygZISuo2WWXb8Qyqt0eVvkk=; b=xPrPc0ZdOTzq3I3MLnQBx177H2eLykP/BnH8IzSUtZjzOlvy6HpNgktNBSB4KC1XII xOcLGpHSJSUXQrj2x/05eL33sXQUHMDun3c2XRUB1ydTs3O5G5C5MIWEGI86KFjDWQqz otMmbdKoNTjWGqo19s9weO8f6xJAcY122T4PG0IHTlxfqUIipeWHNfQAJJ40JPnuVwty tgz6Xh5L7RDfk0T/h+OM0YOOK5C4lPHTzS5QtvM43Y/MUGYQAmUcTiZSeXn+00e0cdwe 5nVZtHZ1hJ+DqU1fyANHwsv3/4lVwAo5LNdK0tOwxyyZKCGg/DhK8VFEs0pGAteD6NbP rp/g== X-Gm-Message-State: AOJu0Yx6Eu0w2ID8WxDdWGdqFDSMQUBp5pYGMnxvbO7PY1NxXxylLCBx nJ43ch/EE/twOv0K0OceHv30x0TqQ4dcMXrW7HleDr9w1W27Xcb/2tFmuTagyNobgOFgvrbXIXD ZvA== X-Received: by 2002:a2e:9859:0:b0:2eb:f0ed:a36d with SMTP id 38308e7fff4ca-2ec5931d44cmr34179111fa.19.1719218986606; Mon, 24 Jun 2024 01:49:46 -0700 (PDT) Received: from localhost (dsl-tkubng21-58c01c-243.dhcp.inet.fi. [88.192.28.243]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2ec4e07e08esm9056611fa.24.2024.06.24.01.49.46 (version=TLS1 cipher=AES128-SHA bits=128/128); Mon, 24 Jun 2024 01:49:46 -0700 (PDT) From: =?utf-8?q?Martin_Storsj=C3=B6?= To: ffmpeg-devel@ffmpeg.org Date: Mon, 24 Jun 2024 11:49:44 +0300 Message-Id: <20240624084944.14276-4-martin@martin.st> X-Mailer: git-send-email 2.39.3 (Apple Git-146) In-Reply-To: <20240624084944.14276-1-martin@martin.st> References: <20240624084944.14276-1-martin@martin.st> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 4/4] hlsenc: Calculate the average and actual maximum bitrate of segments 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: lq@chinaffmpeg.org Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: OCpdUoAajIUk Previously, the bitrate advertised in the master playlist would only be based on the nominal values in either AVCodecParameters bit_rate, or via AVCPBProperties max_bitrate. On top of this, a fudge factor of 10% is added, to account for container overhead. Neither of these bitrates may be known, and if the encoder is running in VBR mode, there is no such value to be known. And the container overhead may be more or less than the given constant factor of 10%. Instead, calculate the maximum bitrate per segment based on what actually gets output from the muxer, and average bitrate across all segments. When muxing of the file finishes, update the master playlist with these values, exposing both the maximum (which previously was a guesstimate based on the nominal values) via EXT-X-STREAM-INF BANDWIDTH, and the average via EXT-X-STREAM-INF AVERAGE-BANDWIDTH. This makes it possible to use the hlsenc muxer with VBR encodes, for VOD style muxing. --- libavformat/dashenc.c | 4 ++-- libavformat/hlsenc.c | 47 ++++++++++++++++++++++++++++----------- libavformat/hlsplaylist.c | 3 +++ libavformat/hlsplaylist.h | 1 + 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index 8c14aa746e..d4a6fe0304 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -1322,7 +1322,7 @@ static int write_manifest(AVFormatContext *s, int final) av_strlcat(codec_str, audio_codec_str, sizeof(codec_str)); } get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); - ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate, + ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate, 0, playlist_file, agroup, codec_str, NULL, NULL); } @@ -1348,7 +1348,7 @@ static int write_manifest(AVFormatContext *s, int final) continue; av_strlcpy(codec_str, os->codec_str, sizeof(codec_str)); get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); - ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate, + ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate, 0, playlist_file, NULL, codec_str, NULL, NULL); } diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 3ca99abdbb..26722c9b32 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -150,6 +150,11 @@ typedef struct VariantStream { int discontinuity; int reference_stream_index; + int64_t total_size; + double total_duration; + int64_t avg_bitrate; + int64_t max_bitrate; + HLSSegment *segments; HLSSegment *last_segment; HLSSegment *old_segments; @@ -1108,6 +1113,16 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, if (!en) return AVERROR(ENOMEM); + vs->total_size += size; + vs->total_duration += duration; + if (duration > 0) { + int cur_bitrate = (int)(8 * size / duration); + if (cur_bitrate > vs->max_bitrate) + vs->max_bitrate = cur_bitrate; + } + if (vs->total_duration > 0) + vs->avg_bitrate = (int)(8 * vs->total_size / vs->total_duration); + en->var_stream_idx = vs->var_stream_idx; ret = sls_flags_filename_process(s, hls, vs, en, duration, pos, size); if (ret < 0) { @@ -1362,14 +1377,15 @@ static int64_t get_stream_bit_rate(AVStream *stream) } static int create_master_playlist(AVFormatContext *s, - VariantStream * const input_vs) + VariantStream * const input_vs, + int final) { HLSContext *hls = s->priv_data; VariantStream *vs, *temp_vs; AVStream *vid_st, *aud_st; AVDictionary *options = NULL; unsigned int i, j; - int ret, bandwidth; + int ret, bandwidth, avg_bandwidth; const char *m3u8_rel_name = NULL; const char *vtt_m3u8_rel_name = NULL; const char *ccgroup; @@ -1389,8 +1405,8 @@ static int create_master_playlist(AVFormatContext *s, return 0; } else { /* Keep publishing the master playlist at the configured rate */ - if (&hls->var_streams[0] != input_vs || !hls->master_publish_rate || - input_vs->number % hls->master_publish_rate) + if ((&hls->var_streams[0] != input_vs || !hls->master_publish_rate || + input_vs->number % hls->master_publish_rate) && !final) return 0; } @@ -1480,12 +1496,17 @@ static int create_master_playlist(AVFormatContext *s, } } - bandwidth = 0; - if (vid_st) - bandwidth += get_stream_bit_rate(vid_st); - if (aud_st) - bandwidth += get_stream_bit_rate(aud_st); - bandwidth += bandwidth / 10; + if (final) { + bandwidth = vs->max_bitrate; + avg_bandwidth = vs->avg_bitrate; + } else { + bandwidth = 0; + if (vid_st) + bandwidth += get_stream_bit_rate(vid_st); + if (aud_st) + bandwidth += get_stream_bit_rate(aud_st); + bandwidth += bandwidth / 10; + } ccgroup = NULL; if (vid_st && vs->ccgroup) { @@ -1514,11 +1535,11 @@ static int create_master_playlist(AVFormatContext *s, } if (!hls->has_default_key || !hls->has_video_m3u8) { - ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, m3u8_rel_name, + ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, avg_bandwidth, m3u8_rel_name, aud_st ? vs->agroup : NULL, vs->codec_attr, ccgroup, sgroup); } else { if (vid_st) { - ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, m3u8_rel_name, + ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, avg_bandwidth, m3u8_rel_name, aud_st ? vs->agroup : NULL, vs->codec_attr, ccgroup, sgroup); } } @@ -1671,7 +1692,7 @@ fail: ff_rename(temp_vtt_filename, vs->vtt_m3u8_name, s); } if (ret >= 0 && hls->master_pl_name) - if (create_master_playlist(s, vs) < 0) + if (create_master_playlist(s, vs, last) < 0) av_log(s, AV_LOG_WARNING, "Master playlist creation failed\n"); return ret; diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c index 4f35d0388f..f8a6977702 100644 --- a/libavformat/hlsplaylist.c +++ b/libavformat/hlsplaylist.c @@ -71,6 +71,7 @@ void ff_hls_write_subtitle_rendition(AVIOContext *out, const char *sgroup, } void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth, + int avg_bandwidth, const char *filename, const char *agroup, const char *codecs, const char *ccgroup, const char *sgroup) @@ -85,6 +86,8 @@ void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth, } avio_printf(out, "#EXT-X-STREAM-INF:BANDWIDTH=%d", bandwidth); + if (avg_bandwidth) + avio_printf(out, ",AVERAGE-BANDWIDTH=%d", avg_bandwidth); if (st && st->codecpar->width > 0 && st->codecpar->height > 0) avio_printf(out, ",RESOLUTION=%dx%d", st->codecpar->width, st->codecpar->height); diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h index c2744c227c..d7aa44d8dc 100644 --- a/libavformat/hlsplaylist.h +++ b/libavformat/hlsplaylist.h @@ -43,6 +43,7 @@ void ff_hls_write_subtitle_rendition(AVIOContext *out, const char *sgroup, const char *filename, const char *language, int name_id, int is_default); void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth, + int avg_bandwidth, const char *filename, const char *agroup, const char *codecs, const char *ccgroup, const char *sgroup);