[FFmpeg-devel] [PATCH 11/17] avformat/avc, hevc: Avoid intermediate buffers when parsing annex B
Andreas Rheinhardt
andreas.rheinhardt at gmail.com
Thu Jul 9 22:20:16 EEST 2020
When creating H.264 or HEVC extradata from annex B extradata or when
transforming annex B into HEVC while also filtering parameter sets away,
the whole input has first been transformed into mp4-style H.264/HEVC
in order to simplify parsing at the next step. By using ff_avc_parse_nalu,
one can avoid these intermediate steps (which involved (re)allocations).
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at gmail.com>
---
libavformat/avc.c | 28 ++++++++-----------------
libavformat/hevc.c | 52 +++++++++++++---------------------------------
2 files changed, 23 insertions(+), 57 deletions(-)
diff --git a/libavformat/avc.c b/libavformat/avc.c
index d089051034..98462940ad 100644
--- a/libavformat/avc.c
+++ b/libavformat/avc.c
@@ -147,7 +147,7 @@ int ff_avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size)
int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
{
AVIOContext *sps_pb = NULL, *pps_pb = NULL, *sps_ext_pb = NULL;
- uint8_t *buf, *end, *start;
+ const uint8_t *nal, *nal_end, *end;
uint8_t *sps, *pps, *sps_ext;
uint32_t sps_size = 0, pps_size = 0, sps_ext_size = 0;
int ret, nb_sps = 0, nb_pps = 0, nb_sps_ext = 0;
@@ -162,12 +162,6 @@ int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
return 0;
}
- ret = ff_avc_parse_nal_units_buf(data, &buf, &len);
- if (ret < 0)
- return ret;
- start = buf;
- end = buf + len;
-
ret = avio_open_dyn_buf(&sps_pb);
if (ret < 0)
goto fail;
@@ -179,12 +173,11 @@ int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
goto fail;
/* look for sps and pps */
- while (end - buf > 4) {
- uint32_t size;
- uint8_t nal_type;
- size = FFMIN(AV_RB32(buf), end - buf - 4);
- buf += 4;
- nal_type = buf[0] & 0x1f;
+ nal_end = NULL;
+ end = data + len;
+ while (nal = ff_avc_parse_nalu(&data, &nal_end, end)) {
+ uint32_t size = nal_end - nal;
+ uint8_t nal_type = nal[0] & 0x1f;
if (nal_type == 7) { /* SPS */
nb_sps++;
@@ -193,7 +186,7 @@ int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
goto fail;
}
avio_wb16(sps_pb, size);
- avio_write(sps_pb, buf, size);
+ avio_write(sps_pb, nal, size);
} else if (nal_type == 8) { /* PPS */
nb_pps++;
if (size > UINT16_MAX || nb_pps >= H264_MAX_PPS_COUNT) {
@@ -201,7 +194,7 @@ int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
goto fail;
}
avio_wb16(pps_pb, size);
- avio_write(pps_pb, buf, size);
+ avio_write(pps_pb, nal, size);
} else if (nal_type == 13) { /* SPS_EXT */
nb_sps_ext++;
if (size > UINT16_MAX || nb_sps_ext >= 256) {
@@ -209,10 +202,8 @@ int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
goto fail;
}
avio_wb16(sps_ext_pb, size);
- avio_write(sps_ext_pb, buf, size);
+ avio_write(sps_ext_pb, nal, size);
}
-
- buf += size;
}
sps_size = avio_get_dyn_buf(sps_pb, &sps);
pps_size = avio_get_dyn_buf(pps_pb, &pps);
@@ -252,7 +243,6 @@ fail:
ffio_free_dyn_buf(&sps_pb);
ffio_free_dyn_buf(&pps_pb);
ffio_free_dyn_buf(&sps_ext_pb);
- av_free(start);
return ret;
}
diff --git a/libavformat/hevc.c b/libavformat/hevc.c
index 94eb3a9cb1..095988b7df 100644
--- a/libavformat/hevc.c
+++ b/libavformat/hevc.c
@@ -35,7 +35,7 @@ typedef struct HVCCNALUnitArray {
uint8_t NAL_unit_type;
uint16_t numNalus;
uint16_t *nalUnitLength;
- uint8_t **nalUnit;
+ const uint8_t **nalUnit;
} HVCCNALUnitArray;
typedef struct HEVCDecoderConfigurationRecord {
@@ -657,7 +657,7 @@ static void nal_unit_parse_header(GetBitContext *gb, uint8_t *nal_type)
skip_bits(gb, 9);
}
-static int hvcc_array_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
+static int hvcc_array_add_nal_unit(const uint8_t *nal_buf, uint32_t nal_size,
uint8_t nal_type, int ps_array_completeness,
HEVCDecoderConfigurationRecord *hvcc)
{
@@ -710,7 +710,7 @@ static int hvcc_array_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
return 0;
}
-static int hvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
+static int hvcc_add_nal_unit(const uint8_t *nal_buf, uint32_t nal_size,
int ps_array_completeness,
HEVCDecoderConfigurationRecord *hvcc)
{
@@ -1000,26 +1000,16 @@ int ff_hevc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in,
int size, int filter_ps, int *ps_count)
{
int num_ps = 0, ret = 0;
- uint8_t *buf, *end, *start = NULL;
+ const uint8_t *nal, *nal_end = NULL, *end = buf_in + size;
if (!filter_ps) {
ret = ff_avc_parse_nal_units(pb, buf_in, size);
goto end;
}
- ret = ff_avc_parse_nal_units_buf(buf_in, &start, &size);
- if (ret < 0)
- goto end;
-
- ret = 0;
- buf = start;
- end = start + size;
-
- while (end - buf > 4) {
- uint32_t len = FFMIN(AV_RB32(buf), end - buf - 4);
- uint8_t type = (buf[4] >> 1) & 0x3f;
-
- buf += 4;
+ while (nal = ff_avc_parse_nalu(&buf_in, &nal_end, end)) {
+ uint32_t len = nal_end - nal;
+ uint8_t type = (nal[0] >> 1) & 0x3f;
switch (type) {
case HEVC_NAL_VPS:
@@ -1030,15 +1020,12 @@ int ff_hevc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in,
default:
ret += 4 + len;
avio_wb32(pb, len);
- avio_write(pb, buf, len);
+ avio_write(pb, nal, len);
break;
}
-
- buf += len;
}
end:
- av_free(start);
if (ps_count)
*ps_count = num_ps;
return ret;
@@ -1069,7 +1056,7 @@ int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
int size, int ps_array_completeness)
{
HEVCDecoderConfigurationRecord hvcc;
- uint8_t *buf, *end, *start;
+ const uint8_t *nal, *nal_end = NULL, *end;
int ret;
if (size < 6) {
@@ -1084,20 +1071,12 @@ int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
return AVERROR_INVALIDDATA;
}
- ret = ff_avc_parse_nal_units_buf(data, &start, &size);
- if (ret < 0)
- return ret;
-
hvcc_init(&hvcc);
- buf = start;
- end = start + size;
-
- while (end - buf > 4) {
- uint32_t len = FFMIN(AV_RB32(buf), end - buf - 4);
- uint8_t type = (buf[4] >> 1) & 0x3f;
-
- buf += 4;
+ end = data + size;
+ while (nal = ff_avc_parse_nalu(&data, &nal_end, end)) {
+ uint32_t len = nal_end - nal;
+ uint8_t type = (nal[0] >> 1) & 0x3f;
switch (type) {
case HEVC_NAL_VPS:
@@ -1105,21 +1084,18 @@ int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
case HEVC_NAL_PPS:
case HEVC_NAL_SEI_PREFIX:
case HEVC_NAL_SEI_SUFFIX:
- ret = hvcc_add_nal_unit(buf, len, ps_array_completeness, &hvcc);
+ ret = hvcc_add_nal_unit(nal, len, ps_array_completeness, &hvcc);
if (ret < 0)
goto end;
break;
default:
break;
}
-
- buf += len;
}
ret = hvcc_write(pb, &hvcc);
end:
hvcc_close(&hvcc);
- av_free(start);
return ret;
}
--
2.20.1
More information about the ffmpeg-devel
mailing list