From b177fca06b98f5ca2a2a9f178b49256b32e243e7 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt Date: Sun, 16 Jan 2022 01:17:26 +0100 Subject: avformat/avc: Add functions to split access unit into list of NALUs This will allow to avoid the temporary buffer and memcpys when repacketing annex B to mp4-style H.264/H.265 without searching twice for start codes. Signed-off-by: Andreas Rheinhardt --- libavformat/avc.c | 40 +++++++++++++++++++++++++++++++++++++--- libavformat/avc.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/libavformat/avc.c b/libavformat/avc.c index b5e2921388..b0ceb1d2d8 100644 --- a/libavformat/avc.c +++ b/libavformat/avc.c @@ -70,7 +70,8 @@ const uint8_t *ff_avc_find_startcode(const uint8_t *p, const uint8_t *end){ return out; } -int ff_avc_parse_nal_units(AVIOContext *pb, const uint8_t *buf_in, int size) +static int avc_parse_nal_units(AVIOContext *pb, NALUList *list, + const uint8_t *buf_in, int size) { const uint8_t *p = buf_in; const uint8_t *end = p + size; @@ -79,19 +80,52 @@ int ff_avc_parse_nal_units(AVIOContext *pb, const uint8_t *buf_in, int size) size = 0; nal_start = ff_avc_find_startcode(p, end); for (;;) { + const size_t nalu_limit = SIZE_MAX / sizeof(*list->nalus); while (nal_start < end && !*(nal_start++)); if (nal_start == end) break; nal_end = ff_avc_find_startcode(nal_start, end); - avio_wb32(pb, nal_end - nal_start); - avio_write(pb, nal_start, nal_end - nal_start); + if (pb) { + avio_wb32(pb, nal_end - nal_start); + avio_write(pb, nal_start, nal_end - nal_start); + } else if (list->nb_nalus >= nalu_limit) { + return AVERROR(ERANGE); + } else { + NALU *tmp = av_fast_realloc(list->nalus, &list->nalus_array_size, + (list->nb_nalus + 1) * sizeof(*list->nalus)); + if (!tmp) + return AVERROR(ENOMEM); + list->nalus = tmp; + tmp[list->nb_nalus++] = (NALU){ .offset = nal_start - p, + .size = nal_end - nal_start }; + } size += 4 + nal_end - nal_start; nal_start = nal_end; } return size; } +int ff_avc_parse_nal_units(AVIOContext *pb, const uint8_t *buf_in, int size) +{ + return avc_parse_nal_units(pb, NULL, buf_in, size); +} + +int ff_nal_units_create_list(NALUList *list, const uint8_t *buf, int size) +{ + list->nb_nalus = 0; + return avc_parse_nal_units(NULL, list, buf, size); +} + +void ff_nal_units_write_list(const NALUList *list, AVIOContext *pb, + const uint8_t *buf) +{ + for (unsigned i = 0; i < list->nb_nalus; i++) { + avio_wb32(pb, list->nalus[i].size); + avio_write(pb, buf + list->nalus[i].offset, list->nalus[i].size); + } +} + int ff_avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size) { AVIOContext *pb; diff --git a/libavformat/avc.h b/libavformat/avc.h index 9792b77913..aced285c7a 100644 --- a/libavformat/avc.h +++ b/libavformat/avc.h @@ -25,6 +25,35 @@ #include #include "avio.h" +typedef struct NALU { + int offset; + uint32_t size; +} NALU; + +typedef struct NALUList { + NALU *nalus; + unsigned nalus_array_size; + unsigned nb_nalus; ///< valid entries in nalus +} NALUList; + +/* This function will parse the given annex B buffer and create + * a NALUList from it. This list can be passed to ff_nal_units_write_list() + * to write the access unit reformatted to mp4. + * + * @param list A NALUList. The list->nalus and list->nalus_array_size + * must be valid when calling this function and may be updated. + * nb_nalus is set by this function on success. + * @param buf buffer containing annex B H.264 or H.265. Must be padded. + * @param size size of buf, excluding padding. + * @return < 0 on error, the size of the mp4-style packet on success. + */ +int ff_nal_units_create_list(NALUList *list, const uint8_t *buf, int size); + +/* Writes a NALUList to the specified AVIOContext. The list must originate + * from ff_nal_units_create_list() with the same buf. */ +void ff_nal_units_write_list(const NALUList *list, AVIOContext *pb, + const uint8_t *buf); + int ff_avc_parse_nal_units(AVIOContext *s, const uint8_t *buf, int size); 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); -- cgit v1.2.3