[FFmpeg-devel] [PATCH v2] Extract av_hls_codec_attr
Romain Beauxis
toots at rastageeks.org
Fri Nov 3 07:17:58 EET 2023
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 v1:
- ff_nal_unit_extract_rbsp renamed into avpriv_nal_unit_extract_rbsp to
follow the appropriate library cross-linking convention.
---
libavcodec/Makefile | 2 +
libavcodec/hls.c | 105 +++++++++++++++++++++++++++++++++++++++++++
libavcodec/hls.h | 42 +++++++++++++++++
libavformat/avc.c | 4 +-
libavformat/avc.h | 2 +-
libavformat/hevc.c | 2 +-
libavformat/hlsenc.c | 83 +++-------------------------------
7 files changed, 159 insertions(+), 81 deletions(-)
create mode 100644 libavcodec/hls.c
create mode 100644 libavcodec/hls.h
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 580a8d6b54..b3b2b18980 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -16,6 +16,7 @@ HEADERS = ac3_parser.h \
dirac.h \
dv_profile.h \
dxva2.h \
+ hls.h \
jni.h \
mediacodec.h \
packet.h \
@@ -47,6 +48,7 @@ OBJS = ac3_parser.o \
get_buffer.o \
imgconvert.o \
jni.o \
+ hls.o \
mathtables.o \
mediacodec.o \
mpeg12framerate.o \
diff --git a/libavcodec/hls.c b/libavcodec/hls.c
new file mode 100644
index 0000000000..05a6277dbc
--- /dev/null
+++ b/libavcodec/hls.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.h"
+#include "libavutil/intreadwrite.h"
+#include "libavformat/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 = avpriv_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/libavcodec/hls.h b/libavcodec/hls.h
new file mode 100644
index 0000000000..160e31de13
--- /dev/null
+++ b/libavcodec/hls.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_H
+#define AVCODEC_HLS_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 the codec attributes to
+ * @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/avc.c b/libavformat/avc.c
index b0ceb1d2d8..f85483271b 100644
--- a/libavformat/avc.c
+++ b/libavformat/avc.c
@@ -300,7 +300,7 @@ const uint8_t *ff_avc_mp4_find_startcode(const uint8_t *start,
return start + res;
}
-uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len,
+uint8_t *avpriv_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len,
uint32_t *dst_len, int header_len)
{
uint8_t *dst;
@@ -374,7 +374,7 @@ int ff_avc_decode_sps(H264SPS *sps, const uint8_t *buf, int buf_size)
GetBitContext gb;
uint8_t *rbsp_buf;
- rbsp_buf = ff_nal_unit_extract_rbsp(buf, buf_size, &rbsp_size, 0);
+ rbsp_buf = avpriv_nal_unit_extract_rbsp(buf, buf_size, &rbsp_size, 0);
if (!rbsp_buf)
return AVERROR(ENOMEM);
diff --git a/libavformat/avc.h b/libavformat/avc.h
index 0ce95c194e..0bdaba162b 100644
--- a/libavformat/avc.h
+++ b/libavformat/avc.h
@@ -63,7 +63,7 @@ int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size);
const uint8_t *ff_avc_mp4_find_startcode(const uint8_t *start,
const uint8_t *end,
int nal_length_size);
-uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len,
+uint8_t *avpriv_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len,
uint32_t *dst_len, int header_len);
typedef struct {
diff --git a/libavformat/hevc.c b/libavformat/hevc.c
index ca5187a92e..5ea4280ebe 100644
--- a/libavformat/hevc.c
+++ b/libavformat/hevc.c
@@ -708,7 +708,7 @@ static int hvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
uint8_t *rbsp_buf;
uint32_t rbsp_size;
- rbsp_buf = ff_nal_unit_extract_rbsp(nal_buf, nal_size, &rbsp_size, 2);
+ rbsp_buf = avpriv_nal_unit_extract_rbsp(nal_buf, nal_size, &rbsp_size, 2);
if (!rbsp_buf) {
ret = AVERROR(ENOMEM);
goto end;
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 4ef84c05c1..1c0a35c36d 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -40,6 +40,7 @@
#include "libavutil/time_internal.h"
#include "libavcodec/defs.h"
+#include "libavcodec/hls.h"
#include "avformat.h"
#include "avio_internal.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,
--
2.39.3 (Apple Git-145)
More information about the ffmpeg-devel
mailing list