From patchwork Sun Jun 16 17:00:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Almer X-Patchwork-Id: 49948 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:9196:0:b0:460:55fa:d5ed with SMTP id s22csp1493828vqg; Sun, 16 Jun 2024 10:01:30 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCUzDCpKR+141sWlJkW0TiZIT30S0GtLLNHmTUiwAJygFOWq0ozXt6RqqwJ6CNSVUoYdRTWbklFDOyUAnfsZ45VQb/qSPbKgljY2Kw== X-Google-Smtp-Source: AGHT+IEY8QE2kMxj4AleDu6Sb2grWnjsguFIfBFiQqb0K6Kv0EhE/lM022Ull0FyXxfHtz/WMbEC X-Received: by 2002:a17:907:9487:b0:a6f:6708:d171 with SMTP id a640c23a62f3a-a6f6708d205mr465336466b.3.1718557289711; Sun, 16 Jun 2024 10:01:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1718557289; cv=none; d=google.com; s=arc-20160816; b=FvVmjf8BqVaJdP6Y1xaXB2F4mlPy7k8+hDmnOE/J7f0aazhgBp4J32UHghV0DWMdck 8UJZxYtwAkdUg+vdBrxzF6qQpuHxNVS25ML3x6ZHpkXMF8npOViIx0xRTtuCEeJ1uyEF 67CVZb15b7YFia3gq5kVsh27BdTeraW/fAiQvKhrcf9JvyNB6/6hNRzK48BVaudZKA5H CaNLRoeKUtr1gbZmnA1PUsDQiJTiiF5GiztAzsewKJ5yg+JqJbeplmhKKE63N9VPBfvo Zr85duHGs7LNn0xQPWLySAy/HPoQQUPmk8nn8qE5L0wxNn3+swWixP2BUVP486yXfWUk MbNQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:message-id:date:to:from :dkim-signature:delivered-to; bh=zaQrGJ7WV3EoXPTcMMWc9bwmeQNXYLh//hSREJhUn6Y=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=qniNps6KvShZSvxW5I7+xRhaXZl43E7Y5j41MVJQF9SNd8T0/YW7LwmMvle13xs03f 8oK511yBsYiIIxn1zE7977mQ0Q7HODPN5U8okEGsgQyipSoJDx8r5Gxz9EkLlr2wL9cY 3vWxB0vUWSoNtxfuox2isWg/lvyydyEmb5MwFtFGwGT0qXYvPCdss0wqUKnUmrzS32gk fvZE/sNdkHqna3V9JuzLJ31Kf0+TuXlUrwWW1DyGvxbi/tjYwUBvAKRSGMdjKt3KixCJ 4VL73pDLo5DIQzBjYhFirSamOT7wZp2s6a+LFbof+M1Oq2hiTEFXjVIUivvMxO96WJYW +nAQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20230601 header.b=PmZ8vg2t; 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; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id a640c23a62f3a-a6f694982b8si245801366b.463.2024.06.16.10.01.28; Sun, 16 Jun 2024 10:01:29 -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; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20230601 header.b=PmZ8vg2t; 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; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id BB08268D630; Sun, 16 Jun 2024 20:01:25 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pf1-f178.google.com (mail-pf1-f178.google.com [209.85.210.178]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id AD3C168D630 for ; Sun, 16 Jun 2024 20:01:17 +0300 (EEST) Received: by mail-pf1-f178.google.com with SMTP id d2e1a72fcca58-7041e39a5beso2763499b3a.3 for ; Sun, 16 Jun 2024 10:01:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718557275; x=1719162075; darn=ffmpeg.org; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:from:to:cc:subject:date:message-id:reply-to; bh=s/Ue8Uz5a9AYl1ehfvHSdZNe2wc1FWK9J18NXihjXK8=; b=PmZ8vg2ttF6q8lT3u3kPWmplVRaCgeM8uomDDXTTdgNL8X8RIf+uzHP0hYhCQAnyRM NgLihJgDKft7Xy2s3zHuuSxTGEDWg3HsN2R18sPPiaePU86d+7lDYpcOyBED6klk/uvj 4vdWlvrRW5WEhi6QinTA7MmAWbVwXWdD8TMoSywyAtADaskSf3QQotp+BJ0z2dlKGvyc 7ZYZCe6GGseJscxTbSJ88YH02A39AM3cqmyBie8RK6v5FSJwgw5tjcFFUtWcSooaXLRu PDjKIZQDGQSb76uD9IwQAjDMmxiCQgrQIHuA21YK/HyvhzXFantWZVdZ4/h/Krg08nLQ 1ffg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718557275; x=1719162075; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=s/Ue8Uz5a9AYl1ehfvHSdZNe2wc1FWK9J18NXihjXK8=; b=L8zpZFF2gEyjuLtBdIfZJH8+D2+1yF8en+0QhU9bJvWeNooYofHF0sySB8B+S3qK22 0s/kt0KpvGh1EZE8WDqgblZHjImY/JVgpv/lFRyvRjDHL7Wsqe72O+A1fflWliXlH+iq z+nEhANgTb6Qt0DGHv9ZXXMEqTbv8hQgN/0J1Na9ltK7ZhfkNd8CSF4L3K/z01Ome2zv KiPoPOjw/u6gYJCHK4y7shlOVFI1CcH6WsjUflrK4/4+MaVjUqtO9oSOVA/vReHTPK16 kjUxoJVtDtUNfJSCKOFmlzfO9BEGc9zIWr1iWsHWyVLm/Op+0B1VNXK55KWneF8NxxRT hjxw== X-Gm-Message-State: AOJu0YxvqsNv9yFNqfqVxqUMFUwZGxe6OQLCNaz6v39PmNQ4r7+5vLpy I082kMEJjXOHPegpppWoTDbRN1nrKID0IVOLWHExJk806qhT4SlSwGi/TA== X-Received: by 2002:a05:6a21:3399:b0:1b8:391f:df9a with SMTP id adf61e73a8af0-1bae7fd94f0mr8129436637.22.1718557274059; Sun, 16 Jun 2024 10:01:14 -0700 (PDT) Received: from localhost.localdomain ([190.194.167.233]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-705ef260437sm2365706b3a.85.2024.06.16.10.01.12 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 Jun 2024 10:01:13 -0700 (PDT) From: James Almer To: ffmpeg-devel@ffmpeg.org Date: Sun, 16 Jun 2024 14:00:06 -0300 Message-ID: <20240616170006.2180-1-jamrial@gmail.com> X-Mailer: git-send-email 2.45.2 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avformat: split off generic NAL function helpers into their own file 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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: XM3l22QwDvE5 Signed-off-by: James Almer --- 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 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(pnalus); - 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 +#include + +#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(pnalus); + 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 +#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;