From patchwork Fri Nov 3 14:03:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Romain Beauxis X-Patchwork-Id: 44495 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:671c:b0:181:818d:5e7f with SMTP id q28csp571460pzh; Fri, 3 Nov 2023 07:05:23 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEVgAgD18z6XtVW8iDVwYBvk4bSvQ8ejhVj2VTpS0ByyBoo8IV5s/Kj+tyak4IEsQXICXr1 X-Received: by 2002:a50:a6dd:0:b0:543:8498:fda5 with SMTP id f29-20020a50a6dd000000b005438498fda5mr7526364edc.14.1699020323623; Fri, 03 Nov 2023 07:05:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1699020323; cv=none; d=google.com; s=arc-20160816; b=byJGri3xiyr5bsbK8l/0z989fqX/8JGB1xImW3Jp0pqYnQI/l+8bue8tiwKu6PedWW LqCYz97VvbwKun6wxx9kCnJX7TYOeq5G3ZUm7DbrB3FrKlKwgcf016FBEE1BCB9f1g3f 0V2sAJz0PUKks3P+flJu7VNyVZHJTpavhPwc6vINPhGt6xjJU/C4gxs7XSGd6Oot02BA MQqKDg7a4sWM5FNh8Nz1Ul4sxz+DKhWZY8QX4myhjiqdRgzngzPG9+uKJUaTSD0ezWGv oRIATH8+OQ6fenTt1/B2OMEI/BjNrhPwzIwtLfTDlN5xSIHOVoi7rCoFPonVdiyvi6FR olBQ== 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:message-id:date:to:from :delivered-to; bh=FmfHLyDVxYBlksGoqHqqpZCXfk5U5fAc2JZ41PSVoi4=; fh=Dy2HmWbIgzG07YKb/uJ0dh3GBmODWRQaNOnRjO8Xj4c=; b=gTs1HuAQ1xCYWxg1ZiEZGkFNKTtP+nwjJ6CgvDXH6pBfPsIo7vxg7GvQCioDEU1A/7 tEqWKx+NeMNDudZ4t/J3IeZmzw9RbWoMZI8n2cPoJuWMCruJC9O0XQhvsIZJlkWBdLbP J6RquvzyS4ry/CFKjvX5EM92BmolPwOwL/lxYqJIl97RzK2FLnCI06C+lzhfUrBGvLxM 9xi0HmHn16kV2x5u1mci4OCdMEpu5Yq4Mn9WbGoTzdowNj1UcXb2tSlY/lc9gHWdaZtU JffDpC7/9rT7ozI9vVopmOe7suwz2FHs0lxy4TM96xzcwp9NQ2UDg3odDD658qRcpGxX CxqA== ARC-Authentication-Results: i=1; mx.google.com; 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 t22-20020a50ab56000000b0053de79e8f9esi992980edc.619.2023.11.03.07.05.17; Fri, 03 Nov 2023 07:05:23 -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; 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 E7E6868CD36; Fri, 3 Nov 2023 16:05:13 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qk1-f175.google.com (mail-qk1-f175.google.com [209.85.222.175]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 5A87A68CCFC for ; Fri, 3 Nov 2023 16:05:07 +0200 (EET) Received: by mail-qk1-f175.google.com with SMTP id af79cd13be357-77891670417so33156185a.0 for ; Fri, 03 Nov 2023 07:05:07 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699020305; x=1699625105; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=KSqss3lp4ByU7ZaZBGbkdqDpd/2C3OL5Egmwjky38W4=; b=EkeEvlnoY4fp+169+Y8huZq2YBDupm2MA3H3JMZwXuOJmfL0ArjUjjiD/mgx/4L0e1 nya0cYczr1i8AsDaIaYkXV7N3TcUKSZaIDJzzBGOUdXmvkoKOGUd1hVIqWIsEskhCoLv Xrr1ZUakWqbdBjd0YGiytB/ghw04jc9BlRl9x3Qdze/dBkdW2NPZk61366MCto2nyI41 AJ+dGPH8kj52CrkxxG4hvrKN4hZgijCI2e3v7ZTpsSuJPx8SpXORUEMLpNvkO6xwF/2e 7uva5ib4CCgT13GEgKiEh5JlrQp+MwBY9/k8xme6WT5qX1RMht13k29lEfTAJayg06TS VgRQ== X-Gm-Message-State: AOJu0YzmDp81KUaZG7XN1vZ18bF9KtbIkFVoAEMsBU16r40XCvsndB27 i9gRA25UnGbJ44oSZOWDHV6I9CuX9Btf8g== X-Received: by 2002:a05:620a:1a8e:b0:774:17d6:31f1 with SMTP id bl14-20020a05620a1a8e00b0077417d631f1mr26338310qkb.4.1699020305209; Fri, 03 Nov 2023 07:05:05 -0700 (PDT) Received: from localhost.localdomain (ec2-184-73-39-201.compute-1.amazonaws.com. [184.73.39.201]) by smtp.gmail.com with ESMTPSA id k11-20020a05620a414b00b007777521dca4sm755902qko.21.2023.11.03.07.05.04 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 03 Nov 2023 07:05:04 -0700 (PDT) From: Romain Beauxis To: ffmpeg-devel@ffmpeg.org Date: Fri, 3 Nov 2023 09:03:49 -0500 Message-Id: <20231103140348.94116-1-toots@rastageeks.org> X-Mailer: git-send-email 2.39.3 (Apple Git-145) MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3] Extract av_hls_codec_attr 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: Romain Beauxis Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: iEpDIhLVXZg8 The logic for extracting HLS codec attribute strings is very useful and can be re-used in many different situations when working with HLS streams using libavcodec/libavformat. This patch extracts the function's code and places it into a publicly available function. Differences since v2: - Shared function moved to libavformat, ff_nal_unit_extract_rbsp function kept identical. --- libavformat/Makefile | 2 + libavformat/hls_utils.c | 105 ++++++++++++++++++++++++++++++++++++++++ libavformat/hls_utils.h | 42 ++++++++++++++++ libavformat/hlsenc.c | 83 +++---------------------------- 4 files changed, 155 insertions(+), 77 deletions(-) create mode 100644 libavformat/hls_utils.c create mode 100644 libavformat/hls_utils.h diff --git a/libavformat/Makefile b/libavformat/Makefile index 329055ccfd..5e148e5bbc 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -3,6 +3,7 @@ DESC = FFmpeg container format library HEADERS = avformat.h \ avio.h \ + hls_utils.h \ version.h \ version_major.h \ @@ -15,6 +16,7 @@ OBJS = allformats.o \ dump.o \ dv.o \ format.o \ + hls_utils.o \ id3v1.o \ id3v2.o \ isom_tags.o \ diff --git a/libavformat/hls_utils.c b/libavformat/hls_utils.c new file mode 100644 index 0000000000..df45fbc1a4 --- /dev/null +++ b/libavformat/hls_utils.c @@ -0,0 +1,105 @@ +/* + * HLS public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hls_utils.h" +#include "libavutil/intreadwrite.h" +#include "avc.h" + +int av_hls_codec_attr(AVStream *st, char *attr, size_t attr_len) { + if (st->codecpar->codec_id == AV_CODEC_ID_H264) { + uint8_t *data = st->codecpar->extradata; + if (data) { + const uint8_t *p; + + if (AV_RB32(data) == 0x01 && (data[4] & 0x1F) == 7) + p = &data[5]; + else if (AV_RB24(data) == 0x01 && (data[3] & 0x1F) == 7) + p = &data[4]; + else if (data[0] == 0x01) /* avcC */ + p = &data[1]; + else + return AVERROR_INVALIDDATA; + snprintf(attr, attr_len, + "avc1.%02x%02x%02x", p[0], p[1], p[2]); + } else { + return AVERROR_INVALIDDATA; + } + } else if (st->codecpar->codec_id == AV_CODEC_ID_HEVC) { + uint8_t *data = st->codecpar->extradata; + int profile = AV_PROFILE_UNKNOWN; + int level = AV_LEVEL_UNKNOWN; + + if (st->codecpar->profile != AV_PROFILE_UNKNOWN) + profile = st->codecpar->profile; + if (st->codecpar->level != AV_LEVEL_UNKNOWN) + level = st->codecpar->level; + + /* check the boundary of data which from current position is small than extradata_size */ + while (data && (data - st->codecpar->extradata + 19) < st->codecpar->extradata_size) { + /* get HEVC SPS NAL and seek to profile_tier_level */ + if (!(data[0] | data[1] | data[2]) && data[3] == 1 && ((data[4] & 0x7E) == 0x42)) { + uint8_t *rbsp_buf; + int remain_size = 0; + int rbsp_size = 0; + /* skip start code + nalu header */ + data += 6; + /* process by reference General NAL unit syntax */ + remain_size = st->codecpar->extradata_size - (data - st->codecpar->extradata); + rbsp_buf = ff_nal_unit_extract_rbsp(data, remain_size, &rbsp_size, 0); + if (!rbsp_buf) + return AVERROR_INVALIDDATA; + if (rbsp_size < 13) { + av_freep(&rbsp_buf); + break; + } + /* skip sps_video_parameter_set_id u(4), + * sps_max_sub_layers_minus1 u(3), + * and sps_temporal_id_nesting_flag u(1) */ + profile = rbsp_buf[1] & 0x1f; + /* skip 8 + 8 + 32 + 4 + 43 + 1 bit */ + level = rbsp_buf[12]; + av_freep(&rbsp_buf); + break; + } + data++; + } + if (st->codecpar->codec_tag == MKTAG('h','v','c','1') && + profile != AV_PROFILE_UNKNOWN && + level != AV_LEVEL_UNKNOWN) { + snprintf(attr, attr_len, "%s.%d.4.L%d.B01", av_fourcc2str(st->codecpar->codec_tag), profile, level); + } else + return AVERROR_INVALIDDATA; + } else if (st->codecpar->codec_id == AV_CODEC_ID_MP2) { + snprintf(attr, attr_len, "mp4a.40.33"); + } else if (st->codecpar->codec_id == AV_CODEC_ID_MP3) { + snprintf(attr, attr_len, "mp4a.40.34"); + } else if (st->codecpar->codec_id == AV_CODEC_ID_AAC) { + /* TODO : For HE-AAC, HE-AACv2, the last digit needs to be set to 5 and 29 respectively */ + snprintf(attr, attr_len, "mp4a.40.2"); + } else if (st->codecpar->codec_id == AV_CODEC_ID_AC3) { + snprintf(attr, attr_len, "ac-3"); + } else if (st->codecpar->codec_id == AV_CODEC_ID_EAC3) { + snprintf(attr, attr_len, "ec-3"); + } else { + return AVERROR_INVALIDDATA; + } + + return 0; +} diff --git a/libavformat/hls_utils.h b/libavformat/hls_utils.h new file mode 100644 index 0000000000..c73ed5e320 --- /dev/null +++ b/libavformat/hls_utils.h @@ -0,0 +1,42 @@ +/* + * HLS public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * A public API for HLS codec information + */ + +#ifndef AVCODEC_HLS_UTILS_H +#define AVCODEC_HLS_UTILS_H + +#include "libavformat/avformat.h" + +/** + * Write a NULL-terminated string representing the codec attributes + * associated with the given AVStream. + * + * @param st stream to extract codec attributes from + * @param attr buffer to write to wanted payload size + * @param attr_len size of the buffer + * @return 0 on success, a negative AVERROR code on failure + */ +int av_hls_codec_attr(AVStream *st, char *attr, size_t attr_len); + +#endif diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 4ef84c05c1..095aeab015 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -48,6 +48,7 @@ #include "http.h" #endif #include "hlsplaylist.h" +#include "hls_utils.h" #include "internal.h" #include "mux.h" #include "os_support.h" @@ -344,89 +345,17 @@ static void write_codec_attr(AVStream *st, VariantStream *vs) { int codec_strlen = strlen(vs->codec_attr); char attr[32]; + int ret; if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) return; if (vs->attr_status == CODEC_ATTRIBUTE_WILL_NOT_BE_WRITTEN) return; - if (st->codecpar->codec_id == AV_CODEC_ID_H264) { - uint8_t *data = st->codecpar->extradata; - if (data) { - const uint8_t *p; - - if (AV_RB32(data) == 0x01 && (data[4] & 0x1F) == 7) - p = &data[5]; - else if (AV_RB24(data) == 0x01 && (data[3] & 0x1F) == 7) - p = &data[4]; - else if (data[0] == 0x01) /* avcC */ - p = &data[1]; - else - goto fail; - snprintf(attr, sizeof(attr), - "avc1.%02x%02x%02x", p[0], p[1], p[2]); - } else { - goto fail; - } - } else if (st->codecpar->codec_id == AV_CODEC_ID_HEVC) { - uint8_t *data = st->codecpar->extradata; - int profile = AV_PROFILE_UNKNOWN; - int level = AV_LEVEL_UNKNOWN; - - if (st->codecpar->profile != AV_PROFILE_UNKNOWN) - profile = st->codecpar->profile; - if (st->codecpar->level != AV_LEVEL_UNKNOWN) - level = st->codecpar->level; - - /* check the boundary of data which from current position is small than extradata_size */ - while (data && (data - st->codecpar->extradata + 19) < st->codecpar->extradata_size) { - /* get HEVC SPS NAL and seek to profile_tier_level */ - if (!(data[0] | data[1] | data[2]) && data[3] == 1 && ((data[4] & 0x7E) == 0x42)) { - uint8_t *rbsp_buf; - int remain_size = 0; - int rbsp_size = 0; - /* skip start code + nalu header */ - data += 6; - /* process by reference General NAL unit syntax */ - remain_size = st->codecpar->extradata_size - (data - st->codecpar->extradata); - rbsp_buf = ff_nal_unit_extract_rbsp(data, remain_size, &rbsp_size, 0); - if (!rbsp_buf) - return; - if (rbsp_size < 13) { - av_freep(&rbsp_buf); - break; - } - /* skip sps_video_parameter_set_id u(4), - * sps_max_sub_layers_minus1 u(3), - * and sps_temporal_id_nesting_flag u(1) */ - profile = rbsp_buf[1] & 0x1f; - /* skip 8 + 8 + 32 + 4 + 43 + 1 bit */ - level = rbsp_buf[12]; - av_freep(&rbsp_buf); - break; - } - data++; - } - if (st->codecpar->codec_tag == MKTAG('h','v','c','1') && - profile != AV_PROFILE_UNKNOWN && - level != AV_LEVEL_UNKNOWN) { - snprintf(attr, sizeof(attr), "%s.%d.4.L%d.B01", av_fourcc2str(st->codecpar->codec_tag), profile, level); - } else - goto fail; - } else if (st->codecpar->codec_id == AV_CODEC_ID_MP2) { - snprintf(attr, sizeof(attr), "mp4a.40.33"); - } else if (st->codecpar->codec_id == AV_CODEC_ID_MP3) { - snprintf(attr, sizeof(attr), "mp4a.40.34"); - } else if (st->codecpar->codec_id == AV_CODEC_ID_AAC) { - /* TODO : For HE-AAC, HE-AACv2, the last digit needs to be set to 5 and 29 respectively */ - snprintf(attr, sizeof(attr), "mp4a.40.2"); - } else if (st->codecpar->codec_id == AV_CODEC_ID_AC3) { - snprintf(attr, sizeof(attr), "ac-3"); - } else if (st->codecpar->codec_id == AV_CODEC_ID_EAC3) { - snprintf(attr, sizeof(attr), "ec-3"); - } else { - goto fail; - } + ret = av_hls_codec_attr(st, attr, sizeof(attr)); + if (ret < 0) + goto fail; + // Don't write the same attribute multiple times if (!av_stristr(vs->codec_attr, attr)) { snprintf(vs->codec_attr + codec_strlen,