diff mbox series

[FFmpeg-devel] avformat: split off generic NAL function helpers into their own file

Message ID 20240616170006.2180-1-jamrial@gmail.com
State New
Headers show
Series [FFmpeg-devel] avformat: split off generic NAL function helpers into their own file | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 fail Make fate failed
andriy/make_x86 success Make finished
andriy/make_fate_x86 fail Make fate failed

Commit Message

James Almer June 16, 2024, 5 p.m. UTC
Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavformat/Makefile           |   2 +-
 libavformat/avc.c              | 164 +---------------------------
 libavformat/avc.h              |  37 -------
 libavformat/flvenc.c           |   3 +-
 libavformat/hevc.c             |   7 +-
 libavformat/hlsenc.c           |   1 +
 libavformat/matroskaenc.c      |   1 +
 libavformat/movenc.c           |   5 +-
 libavformat/movenccenc.c       |   5 +-
 libavformat/mxfenc.c           |   3 +-
 libavformat/nal.c              | 190 +++++++++++++++++++++++++++++++++
 libavformat/nal.h              |  66 ++++++++++++
 libavformat/rtpenc_h264_hevc.c |   9 +-
 libavformat/sdp.c              |   5 +-
 libavformat/vvc.c              |   7 +-
 15 files changed, 287 insertions(+), 218 deletions(-)
 create mode 100644 libavformat/nal.c
 create mode 100644 libavformat/nal.h

Comments

Michael Niedermayer June 18, 2024, 9:23 p.m. UTC | #1
On Sun, Jun 16, 2024 at 02:00:06PM -0300, James Almer wrote:
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
>  libavformat/Makefile           |   2 +-
>  libavformat/avc.c              | 164 +---------------------------
>  libavformat/avc.h              |  37 -------
>  libavformat/flvenc.c           |   3 +-
>  libavformat/hevc.c             |   7 +-
>  libavformat/hlsenc.c           |   1 +
>  libavformat/matroskaenc.c      |   1 +
>  libavformat/movenc.c           |   5 +-
>  libavformat/movenccenc.c       |   5 +-
>  libavformat/mxfenc.c           |   3 +-
>  libavformat/nal.c              | 190 +++++++++++++++++++++++++++++++++
>  libavformat/nal.h              |  66 ++++++++++++
>  libavformat/rtpenc_h264_hevc.c |   9 +-
>  libavformat/sdp.c              |   5 +-
>  libavformat/vvc.c              |   7 +-
>  15 files changed, 287 insertions(+), 218 deletions(-)
>  create mode 100644 libavformat/nal.c
>  create mode 100644 libavformat/nal.h

TEST    source
--- ./tests/ref/fate/source	2024-06-16 09:48:55.353888202 +0200
+++ tests/data/fate/source	2024-06-18 23:22:19.071495178 +0200
@@ -25,6 +25,7 @@
 compat/float/float.h
 compat/float/limits.h
 libavcodec/bitstream_template.h
+libavformat/nal.h
 tools/decode_simple.h
 Use of av_clip() where av_clip_uintp2() could be used:
 Use of av_clip() where av_clip_intp2() could be used:


[...]
James Almer June 19, 2024, 1:04 p.m. UTC | #2
On 6/18/2024 6:23 PM, Michael Niedermayer wrote:
> On Sun, Jun 16, 2024 at 02:00:06PM -0300, James Almer wrote:
>> Signed-off-by: James Almer <jamrial@gmail.com>
>> ---
>>   libavformat/Makefile           |   2 +-
>>   libavformat/avc.c              | 164 +---------------------------
>>   libavformat/avc.h              |  37 -------
>>   libavformat/flvenc.c           |   3 +-
>>   libavformat/hevc.c             |   7 +-
>>   libavformat/hlsenc.c           |   1 +
>>   libavformat/matroskaenc.c      |   1 +
>>   libavformat/movenc.c           |   5 +-
>>   libavformat/movenccenc.c       |   5 +-
>>   libavformat/mxfenc.c           |   3 +-
>>   libavformat/nal.c              | 190 +++++++++++++++++++++++++++++++++
>>   libavformat/nal.h              |  66 ++++++++++++
>>   libavformat/rtpenc_h264_hevc.c |   9 +-
>>   libavformat/sdp.c              |   5 +-
>>   libavformat/vvc.c              |   7 +-
>>   15 files changed, 287 insertions(+), 218 deletions(-)
>>   create mode 100644 libavformat/nal.c
>>   create mode 100644 libavformat/nal.h
> 
> TEST    source
> --- ./tests/ref/fate/source	2024-06-16 09:48:55.353888202 +0200
> +++ tests/data/fate/source	2024-06-18 23:22:19.071495178 +0200
> @@ -25,6 +25,7 @@
>   compat/float/float.h
>   compat/float/limits.h
>   libavcodec/bitstream_template.h
> +libavformat/nal.h
>   tools/decode_simple.h
>   Use of av_clip() where av_clip_uintp2() could be used:
>   Use of av_clip() where av_clip_intp2() could be used:

Copy-paste mistake in the header define. Fixed locally.
Vittorio Giovara June 20, 2024, 10:18 a.m. UTC | #3
On Sun, Jun 16, 2024 at 7:09 PM James Almer <jamrial@gmail.com> wrote:

> diff --git a/libavformat/nal.h b/libavformat/nal.h
> new file mode 100644
> index 0000000000..ce49ea70b0
> --- /dev/null
> +++ b/libavformat/nal.h
> @@ -0,0 +1,66 @@
> +/*
> + * NAL helper functions for muxers
> + *
> + * 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
> + */
> +
> +#ifndef AVFORMAT_NAL_H
> +#define AVFORMAT_AVC_H
>

s/AVFORMAT_AVC_H/AVFORMAT_NAL_H/

Looks good! Do you think any of the parsing code could be reused in lavc
too?
diff mbox series

Patch

diff --git a/libavformat/Makefile b/libavformat/Makefile
index af31d6f795..7ca68a7036 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -35,7 +35,7 @@  OBJS-$(HAVE_LIBC_MSVCRT)                 += file_open.o
 
 # subsystems
 OBJS-$(CONFIG_ISO_MEDIA)                 += isom.o
-OBJS-$(CONFIG_ISO_WRITER)                += av1.o avc.o hevc.o vvc.o vpcc.o
+OBJS-$(CONFIG_ISO_WRITER)                += av1.o avc.o hevc.o nal.o vvc.o vpcc.o
 OBJS-$(CONFIG_IAMFDEC)                   += iamf_reader.o iamf_parse.o iamf.o
 OBJS-$(CONFIG_IAMFENC)                   += iamf_writer.o iamf.o
 OBJS-$(CONFIG_NETWORK)                   += network.o
diff --git a/libavformat/avc.c b/libavformat/avc.c
index 047ea88077..e4040928cd 100644
--- a/libavformat/avc.c
+++ b/libavformat/avc.c
@@ -26,118 +26,7 @@ 
 #include "avio.h"
 #include "avc.h"
 #include "avio_internal.h"
-
-static const uint8_t *avc_find_startcode_internal(const uint8_t *p, const uint8_t *end)
-{
-    const uint8_t *a = p + 4 - ((intptr_t)p & 3);
-
-    for (end -= 3; p < a && p < end; p++) {
-        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
-            return p;
-    }
-
-    for (end -= 3; p < end; p += 4) {
-        uint32_t x = *(const uint32_t*)p;
-//      if ((x - 0x01000100) & (~x) & 0x80008000) // little endian
-//      if ((x - 0x00010001) & (~x) & 0x00800080) // big endian
-        if ((x - 0x01010101) & (~x) & 0x80808080) { // generic
-            if (p[1] == 0) {
-                if (p[0] == 0 && p[2] == 1)
-                    return p;
-                if (p[2] == 0 && p[3] == 1)
-                    return p+1;
-            }
-            if (p[3] == 0) {
-                if (p[2] == 0 && p[4] == 1)
-                    return p+2;
-                if (p[4] == 0 && p[5] == 1)
-                    return p+3;
-            }
-        }
-    }
-
-    for (end += 3; p < end; p++) {
-        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
-            return p;
-    }
-
-    return end + 3;
-}
-
-const uint8_t *ff_avc_find_startcode(const uint8_t *p, const uint8_t *end){
-    const uint8_t *out = avc_find_startcode_internal(p, end);
-    if(p<out && out<end && !out[-1]) out--;
-    return out;
-}
-
-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;
-    const uint8_t *nal_start, *nal_end;
-
-    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);
-        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;
-    int ret = avio_open_dyn_buf(&pb);
-    if(ret < 0)
-        return ret;
-
-    ff_avc_parse_nal_units(pb, buf_in, *size);
-
-    *size = avio_close_dyn_buf(pb, buf);
-    return 0;
-}
+#include "nal.h"
 
 int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
 {
@@ -157,7 +46,7 @@  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);
+    ret = ff_nal_parse_units_buf(data, &buf, &len);
     if (ret < 0)
         return ret;
     start = buf;
@@ -283,55 +172,6 @@  int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size)
     return 0;
 }
 
-const uint8_t *ff_avc_mp4_find_startcode(const uint8_t *start,
-                                         const uint8_t *end,
-                                         int nal_length_size)
-{
-    unsigned int res = 0;
-
-    if (end - start < nal_length_size)
-        return NULL;
-    while (nal_length_size--)
-        res = (res << 8) | *start++;
-
-    if (res > end - start)
-        return NULL;
-
-    return start + res;
-}
-
-uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len,
-                                  uint32_t *dst_len, int header_len)
-{
-    uint8_t *dst;
-    uint32_t i, len;
-
-    dst = av_malloc(src_len + AV_INPUT_BUFFER_PADDING_SIZE);
-    if (!dst)
-        return NULL;
-
-    /* NAL unit header */
-    i = len = 0;
-    while (i < header_len && i < src_len)
-        dst[len++] = src[i++];
-
-    while (i + 2 < src_len)
-        if (!src[i] && !src[i + 1] && src[i + 2] == 3) {
-            dst[len++] = src[i++];
-            dst[len++] = src[i++];
-            i++; // remove emulation_prevention_three_byte
-        } else
-            dst[len++] = src[i++];
-
-    while (i < src_len)
-        dst[len++] = src[i++];
-
-    memset(dst + len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
-
-    *dst_len = len;
-    return dst;
-}
-
 static const AVRational avc_sample_aspect_ratio[17] = {
     {   0,  1 },
     {   1,  1 },
diff --git a/libavformat/avc.h b/libavformat/avc.h
index 0ce95c194e..e36108afce 100644
--- a/libavformat/avc.h
+++ b/libavformat/avc.h
@@ -26,45 +26,8 @@ 
 #include "libavutil/rational.h"
 #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);
-const uint8_t *ff_avc_find_startcode(const uint8_t *p, const uint8_t *end);
 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,
-                                  uint32_t *dst_len, int header_len);
 
 typedef struct {
     uint8_t id;
diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
index aba1d7d80b..f34df61c0e 100644
--- a/libavformat/flvenc.c
+++ b/libavformat/flvenc.c
@@ -36,6 +36,7 @@ 
 #include "avformat.h"
 #include "flv.h"
 #include "internal.h"
+#include "nal.h"
 #include "mux.h"
 #include "libavutil/opt.h"
 #include "libavcodec/put_bits.h"
@@ -1076,7 +1077,7 @@  static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
     if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4) {
         /* check if extradata looks like mp4 formatted */
         if (par->extradata_size > 0 && *(uint8_t*)par->extradata != 1)
-            if ((ret = ff_avc_parse_nal_units_buf(pkt->data, &data, &size)) < 0)
+            if ((ret = ff_nal_parse_units_buf(pkt->data, &data, &size)) < 0)
                 return ret;
     } else if (par->codec_id == AV_CODEC_ID_HEVC) {
         if (par->extradata_size > 0 && *(uint8_t*)par->extradata != 1)
diff --git a/libavformat/hevc.c b/libavformat/hevc.c
index 8ab0155f63..d6b9d233d9 100644
--- a/libavformat/hevc.c
+++ b/libavformat/hevc.c
@@ -27,6 +27,7 @@ 
 #include "avio.h"
 #include "avio_internal.h"
 #include "hevc.h"
+#include "nal.h"
 
 #define MAX_SPATIAL_SEGMENTATION 4096 // max. value of u(12) field
 
@@ -978,11 +979,11 @@  int ff_hevc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in,
     uint8_t *buf, *end, *start = NULL;
 
     if (!filter_ps) {
-        ret = ff_avc_parse_nal_units(pb, buf_in, size);
+        ret = ff_nal_parse_units(pb, buf_in, size);
         goto end;
     }
 
-    ret = ff_avc_parse_nal_units_buf(buf_in, &start, &size);
+    ret = ff_nal_parse_units_buf(buf_in, &start, &size);
     if (ret < 0)
         goto end;
 
@@ -1059,7 +1060,7 @@  int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
         return AVERROR_INVALIDDATA;
     }
 
-    ret = ff_avc_parse_nal_units_buf(data, &start, &size);
+    ret = ff_nal_parse_units_buf(data, &start, &size);
     if (ret < 0)
         return ret;
 
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 8a43ef6232..f5c0243cf1 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -50,6 +50,7 @@ 
 #endif
 #include "hlsplaylist.h"
 #include "internal.h"
+#include "nal.h"
 #include "mux.h"
 #include "os_support.h"
 #include "url.h"
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 76c542d50b..094cf61357 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -33,6 +33,7 @@ 
 #include "flacenc.h"
 #include "internal.h"
 #include "isom.h"
+#include "nal.h"
 #include "matroska.h"
 #include "mux.h"
 #include "riff.h"
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 86c1b1da2c..a6d6e00cde 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -63,6 +63,7 @@ 
 #include "libavutil/uuid.h"
 #include "hevc.h"
 #include "rtpenc.h"
+#include "nal.h"
 #include "mov_chan.h"
 #include "movenc_ttml.h"
 #include "mux.h"
@@ -6376,7 +6377,7 @@  int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
         /* from x264 or from bytestream H.264 */
         /* NAL reformatting needed */
         if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
-            ret = ff_avc_parse_nal_units_buf(pkt->data, &reformatted_data,
+            ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
                                              &size);
             if (ret < 0)
                 return ret;
@@ -6389,7 +6390,7 @@  int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
                     goto err;
                 }
             } else {
-                size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size);
+                size = ff_nal_parse_units(pb, pkt->data, pkt->size);
             }
         }
     } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->vos_len > 6 &&
diff --git a/libavformat/movenccenc.c b/libavformat/movenccenc.c
index ce79c0dc3b..1b7a773808 100644
--- a/libavformat/movenccenc.c
+++ b/libavformat/movenccenc.c
@@ -24,6 +24,7 @@ 
 #include "avio_internal.h"
 #include "movenc.h"
 #include "avc.h"
+#include "nal.h"
 
 static int auxiliary_info_alloc_size(MOVMuxCencContext* ctx, int size)
 {
@@ -204,13 +205,13 @@  int ff_mov_cenc_avc_parse_nal_units(MOVMuxCencContext* ctx, AVIOContext *pb,
     }
 
     size = 0;
-    nal_start = ff_avc_find_startcode(p, end);
+    nal_start = ff_nal_find_startcode(p, end);
     for (;;) {
         while (nal_start < end && !*(nal_start++));
         if (nal_start == end)
             break;
 
-        nal_end = ff_avc_find_startcode(nal_start, end);
+        nal_end = ff_nal_find_startcode(nal_start, end);
 
         avio_wb32(pb, nal_end - nal_start);
         avio_w8(pb, *nal_start);
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index f424858fc4..7ba1fe061e 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -60,6 +60,7 @@ 
 #include "avio_internal.h"
 #include "internal.h"
 #include "avc.h"
+#include "nal.h"
 #include "mux.h"
 #include "mxf.h"
 #include "config.h"
@@ -2477,7 +2478,7 @@  static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st,
             if (mxf->header_written)
                 break;
 
-            nal_end = ff_avc_find_startcode(buf, buf_end);
+            nal_end = ff_nal_find_startcode(buf, buf_end);
             ret = ff_avc_decode_sps(sps, buf, nal_end - buf);
             if (ret < 0) {
                 av_log(s, AV_LOG_ERROR, "error parsing sps\n");
diff --git a/libavformat/nal.c b/libavformat/nal.c
new file mode 100644
index 0000000000..26dc5fe688
--- /dev/null
+++ b/libavformat/nal.c
@@ -0,0 +1,190 @@ 
+/*
+ * NAL helper functions for muxers
+ *
+ * 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 <stdint.h>
+#include <string.h>
+
+#include "libavutil/mem.h"
+#include "libavutil/error.h"
+#include "libavcodec/defs.h"
+#include "avio.h"
+#include "avio_internal.h"
+#include "nal.h"
+
+static const uint8_t *nal_find_startcode_internal(const uint8_t *p, const uint8_t *end)
+{
+    const uint8_t *a = p + 4 - ((intptr_t)p & 3);
+
+    for (end -= 3; p < a && p < end; p++) {
+        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
+            return p;
+    }
+
+    for (end -= 3; p < end; p += 4) {
+        uint32_t x = *(const uint32_t*)p;
+//      if ((x - 0x01000100) & (~x) & 0x80008000) // little endian
+//      if ((x - 0x00010001) & (~x) & 0x00800080) // big endian
+        if ((x - 0x01010101) & (~x) & 0x80808080) { // generic
+            if (p[1] == 0) {
+                if (p[0] == 0 && p[2] == 1)
+                    return p;
+                if (p[2] == 0 && p[3] == 1)
+                    return p+1;
+            }
+            if (p[3] == 0) {
+                if (p[2] == 0 && p[4] == 1)
+                    return p+2;
+                if (p[4] == 0 && p[5] == 1)
+                    return p+3;
+            }
+        }
+    }
+
+    for (end += 3; p < end; p++) {
+        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
+            return p;
+    }
+
+    return end + 3;
+}
+
+const uint8_t *ff_nal_find_startcode(const uint8_t *p, const uint8_t *end){
+    const uint8_t *out = nal_find_startcode_internal(p, end);
+    if(p<out && out<end && !out[-1]) out--;
+    return out;
+}
+
+static int nal_parse_units(AVIOContext *pb, NALUList *list,
+                           const uint8_t *buf_in, int size)
+{
+    const uint8_t *p = buf_in;
+    const uint8_t *end = p + size;
+    const uint8_t *nal_start, *nal_end;
+
+    size = 0;
+    nal_start = ff_nal_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_nal_find_startcode(nal_start, end);
+        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_nal_parse_units(AVIOContext *pb, const uint8_t *buf_in, int size)
+{
+    return nal_parse_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 nal_parse_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_nal_parse_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size)
+{
+    AVIOContext *pb;
+    int ret = avio_open_dyn_buf(&pb);
+    if(ret < 0)
+        return ret;
+
+    ff_nal_parse_units(pb, buf_in, *size);
+
+    *size = avio_close_dyn_buf(pb, buf);
+    return 0;
+}
+
+const uint8_t *ff_nal_mp4_find_startcode(const uint8_t *start,
+                                         const uint8_t *end,
+                                         int nal_length_size)
+{
+    unsigned int res = 0;
+
+    if (end - start < nal_length_size)
+        return NULL;
+    while (nal_length_size--)
+        res = (res << 8) | *start++;
+
+    if (res > end - start)
+        return NULL;
+
+    return start + res;
+}
+
+uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len,
+                                  uint32_t *dst_len, int header_len)
+{
+    uint8_t *dst;
+    uint32_t i, len;
+
+    dst = av_malloc(src_len + AV_INPUT_BUFFER_PADDING_SIZE);
+    if (!dst)
+        return NULL;
+
+    /* NAL unit header */
+    i = len = 0;
+    while (i < header_len && i < src_len)
+        dst[len++] = src[i++];
+
+    while (i + 2 < src_len)
+        if (!src[i] && !src[i + 1] && src[i + 2] == 3) {
+            dst[len++] = src[i++];
+            dst[len++] = src[i++];
+            i++; // remove emulation_prevention_three_byte
+        } else
+            dst[len++] = src[i++];
+
+    while (i < src_len)
+        dst[len++] = src[i++];
+
+    memset(dst + len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+
+    *dst_len = len;
+    return dst;
+}
diff --git a/libavformat/nal.h b/libavformat/nal.h
new file mode 100644
index 0000000000..ce49ea70b0
--- /dev/null
+++ b/libavformat/nal.h
@@ -0,0 +1,66 @@ 
+/*
+ * NAL helper functions for muxers
+ *
+ * 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
+ */
+
+#ifndef AVFORMAT_NAL_H
+#define AVFORMAT_AVC_H
+
+#include <stdint.h>
+#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);
+
+const uint8_t *ff_nal_find_startcode(const uint8_t *p, const uint8_t *end);
+const uint8_t *ff_nal_mp4_find_startcode(const uint8_t *start,
+                                         const uint8_t *end,
+                                         int nal_length_size);
+
+int ff_nal_parse_units(AVIOContext *s, const uint8_t *buf, int size);
+int ff_nal_parse_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size);
+
+uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len,
+                                  uint32_t *dst_len, int header_len);
+#endif /* AVFORMAT_NAL_H */
diff --git a/libavformat/rtpenc_h264_hevc.c b/libavformat/rtpenc_h264_hevc.c
index 0c88fc2a23..4d222dca75 100644
--- a/libavformat/rtpenc_h264_hevc.c
+++ b/libavformat/rtpenc_h264_hevc.c
@@ -31,6 +31,7 @@ 
 
 #include "avformat.h"
 #include "avc.h"
+#include "nal.h"
 #include "rtpenc.h"
 
 static void flush_buffered(AVFormatContext *s1, int last)
@@ -185,20 +186,20 @@  void ff_rtp_send_h264_hevc(AVFormatContext *s1, const uint8_t *buf1, int size)
     s->timestamp = s->cur_timestamp;
     s->buf_ptr   = s->buf;
     if (s->nal_length_size)
-        r = ff_avc_mp4_find_startcode(buf1, end, s->nal_length_size) ? buf1 : end;
+        r = ff_nal_mp4_find_startcode(buf1, end, s->nal_length_size) ? buf1 : end;
     else
-        r = ff_avc_find_startcode(buf1, end);
+        r = ff_nal_find_startcode(buf1, end);
     while (r < end) {
         const uint8_t *r1;
 
         if (s->nal_length_size) {
-            r1 = ff_avc_mp4_find_startcode(r, end, s->nal_length_size);
+            r1 = ff_nal_mp4_find_startcode(r, end, s->nal_length_size);
             if (!r1)
                 r1 = end;
             r += s->nal_length_size;
         } else {
             while (!*(r++));
-            r1 = ff_avc_find_startcode(r, end);
+            r1 = ff_nal_find_startcode(r, end);
         }
         nal_send(s1, r, r1 - r, r1 == end);
         r = r1;
diff --git a/libavformat/sdp.c b/libavformat/sdp.c
index ccfaa8aff5..a9e964bae1 100644
--- a/libavformat/sdp.c
+++ b/libavformat/sdp.c
@@ -33,6 +33,7 @@ 
 #include "internal.h"
 #include "avc.h"
 #include "hevc.h"
+#include "nal.h"
 #include "rtp.h"
 #include "version.h"
 #if CONFIG_NETWORK
@@ -190,14 +191,14 @@  static int extradata2psets(AVFormatContext *s, const AVCodecParameters *par,
     }
     memcpy(psets, pset_string, strlen(pset_string));
     p = psets + strlen(pset_string);
-    r = ff_avc_find_startcode(extradata, extradata + extradata_size);
+    r = ff_nal_find_startcode(extradata, extradata + extradata_size);
     while (r < extradata + extradata_size) {
         const uint8_t *r1;
         uint8_t nal_type;
 
         while (!*(r++));
         nal_type = *r & 0x1f;
-        r1 = ff_avc_find_startcode(r, extradata + extradata_size);
+        r1 = ff_nal_find_startcode(r, extradata + extradata_size);
         if (nal_type != 7 && nal_type != 8) { /* Only output SPS and PPS */
             r = r1;
             continue;
diff --git a/libavformat/vvc.c b/libavformat/vvc.c
index 3a686c9910..b293ff46de 100644
--- a/libavformat/vvc.c
+++ b/libavformat/vvc.c
@@ -30,6 +30,7 @@ 
 #include "avc.h"
 #include "avio.h"
 #include "avio_internal.h"
+#include "nal.h"
 #include "vvc.h"
 
 enum {
@@ -813,11 +814,11 @@  int ff_vvc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in,
     uint8_t *buf, *end, *start = NULL;
 
     if (!filter_ps) {
-        ret = ff_avc_parse_nal_units(pb, buf_in, size);
+        ret = ff_nal_parse_units(pb, buf_in, size);
         goto end;
     }
 
-    ret = ff_avc_parse_nal_units_buf(buf_in, &start, &size);
+    ret = ff_nal_parse_units_buf(buf_in, &start, &size);
     if (ret < 0)
         goto end;
 
@@ -894,7 +895,7 @@  int ff_isom_write_vvcc(AVIOContext *pb, const uint8_t *data,
         return AVERROR_INVALIDDATA;
     }
 
-    ret = ff_avc_parse_nal_units_buf(data, &start, &size);
+    ret = ff_nal_parse_units_buf(data, &start, &size);
     if (ret < 0)
         return ret;