This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 0cd4bb2f9630fda825a009d8881e258386af1a85 Author: James Almer <[email protected]> AuthorDate: Mon Mar 2 18:10:39 2026 -0300 Commit: James Almer <[email protected]> CommitDate: Sat Mar 7 19:22:40 2026 -0300 avcodec: add an LCEVC parser Signed-off-by: James Almer <[email protected]> --- Changelog | 1 + libavcodec/Makefile | 1 + libavcodec/lcevc_parser.c | 290 ++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/parsers.c | 1 + libavcodec/version.h | 4 +- 5 files changed, 295 insertions(+), 2 deletions(-) diff --git a/Changelog b/Changelog index cdda717219..6c90b02063 100644 --- a/Changelog +++ b/Changelog @@ -28,6 +28,7 @@ version <next>: - Add vf_deinterlace_d3d12 filter - ffprobe: only show refs field in stream section when reading frames - ProRes Vulkan encoder +- LCEVC parser version 8.0: diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 7b57fe4564..12a8265025 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1277,6 +1277,7 @@ OBJS-$(CONFIG_IPU_PARSER) += ipu_parser.o OBJS-$(CONFIG_JPEG2000_PARSER) += jpeg2000_parser.o OBJS-$(CONFIG_JPEGXL_PARSER) += jpegxl_parser.o jpegxl_parse.o OBJS-$(CONFIG_JPEGXS_PARSER) += jpegxs_parser.o +OBJS-$(CONFIG_LCEVC_PARSER) += lcevc_parser.o OBJS-$(CONFIG_MISC4_PARSER) += misc4_parser.o OBJS-$(CONFIG_MJPEG_PARSER) += mjpeg_parser.o OBJS-$(CONFIG_MLP_PARSER) += mlp_parse.o mlp_parser.o mlp.o diff --git a/libavcodec/lcevc_parser.c b/libavcodec/lcevc_parser.c new file mode 100644 index 0000000000..77888a3efc --- /dev/null +++ b/libavcodec/lcevc_parser.c @@ -0,0 +1,290 @@ +/* + * 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 "libavutil/mem.h" + +#include "avcodec.h" +#include "bytestream.h" +#include "get_bits.h" +#include "h2645_parse.h" +#include "lcevc.h" +#include "parser.h" +#include "parser_internal.h" + +#define START_CODE 0x000001 ///< start_code_prefix_one_3bytes + +typedef struct LCEVCParserContext { + ParseContext pc; + + H2645Packet pkt; + + int parsed_extradata; + int is_lvcc; + int nal_length_size; +} LCEVCParserContext; + +static int lcevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf, + int buf_size) +{ + LCEVCParserContext *ctx = s->priv_data; + ParseContext *pc = &ctx->pc; + + for (int i = 0; i < buf_size; i++) { + int nut; + + pc->state = (pc->state << 8) | buf[i]; + + if (((pc->state >> 8) & 0xFFFFFF) != START_CODE) + continue; + + nut = (pc->state >> 1) & 0x1F; + + // Beginning of access unit + if (nut == LCEVC_IDR_NUT || nut == LCEVC_NON_IDR_NUT) { + if (!pc->frame_start_found) + pc->frame_start_found = 1; + else { + pc->frame_start_found = 0; + return i - 3; + } + } + } + + return END_NOT_FOUND; +} + +static const enum AVPixelFormat pix_fmts[4][4] = { + { AV_PIX_FMT_GRAY8, AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, }, + { AV_PIX_FMT_GRAY10, AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, }, + { AV_PIX_FMT_GRAY12, AV_PIX_FMT_YUV420P12, + AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, }, + { AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV420P14, + AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, }, +}; + +static const struct { + int width; + int height; +} resolution_type_lut[63] = { + { 0, 0}, + { 360, 200 }, { 400, 240 }, { 480, 320 }, { 640, 360 }, + { 640, 480 }, { 768, 480 }, { 800, 600 }, { 852, 480 }, + { 854, 480 }, { 856, 480 }, { 960, 540 }, { 960, 640 }, + { 1024, 576 }, { 1024, 600 }, { 1024, 768 }, { 1152, 864 }, + { 1280, 720 }, { 1280, 800 }, { 1280, 1024 }, { 1360, 768 }, + { 1366, 768 }, { 1920, 1200 }, { 2048, 1080 }, { 2048, 1152 }, + { 2048, 1536 }, { 2160, 1440 }, { 2560, 1440 }, { 2560, 1600 }, + { 2560, 2048 }, { 3200, 1800 }, { 3200, 2048 }, { 3200, 2400 }, + { 3440, 1440 }, { 3840, 1600 }, { 3840, 2160 }, { 3840, 2400 }, + { 4096, 2160 }, { 4096, 3072 }, { 5120, 2880 }, { 5120, 3200 }, + { 5120, 4096 }, { 6400, 4096 }, { 6400, 4800 }, { 7680, 4320 }, + { 7680, 4800 }, +}; + +static inline uint64_t get_mb(GetBitContext *s) { + int more, i = 0; + uint64_t mb = 0; + + do { + int byte = get_bits(s, 8); + unsigned bits = byte & 0x7f; + more = byte & 0x80; + mb = (mb << 7) | bits; + if (++i == 10) + break; + } while (more); + + return mb; +} + +static int parse_nal_unit(AVCodecParserContext *s, AVCodecContext *avctx, + const H2645NAL *nal) +{ + GetByteContext gbc; + bytestream2_init(&gbc, nal->data, nal->size); + bytestream2_skip(&gbc, 2); + + while (bytestream2_get_bytes_left(&gbc) > 1) { + GetBitContext gb; + int payload_size_type, payload_type, payload_size; + int block_size; + + init_get_bits8(&gb, gbc.buffer, bytestream2_get_bytes_left(&gbc)); + + payload_size_type = get_bits(&gb, 3); + payload_type = get_bits(&gb, 5); + payload_size = payload_size_type; + if (payload_size_type == 6) + return AVERROR_PATCHWELCOME; + if (payload_size_type == 7) + payload_size = get_mb(&gb); + + block_size = payload_size + (get_bits_count(&gb) >> 3); + if (block_size >= bytestream2_get_bytes_left(&gbc)) + return AVERROR_INVALIDDATA; + + switch (payload_type) { + case LCEVC_PAYLOAD_TYPE_SEQUENCE_CONFIG: + avctx->profile = get_bits(&gb, 4); + avctx->level = get_bits(&gb, 4); + break; + case LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG: { + int resolution_type, chroma_format_idc, bit_depth; + int processed_planes_type_flag; + + processed_planes_type_flag = get_bits1(&gb); + resolution_type = get_bits(&gb, 6); + skip_bits1(&gb); + chroma_format_idc = get_bits(&gb, 2); + skip_bits(&gb, 2); + bit_depth = get_bits(&gb, 2); // enhancement_depth_type + + s->format = pix_fmts[bit_depth][chroma_format_idc]; + + if (resolution_type < 63) { + s->width = resolution_type_lut[resolution_type].width; + s->height = resolution_type_lut[resolution_type].height; + } else { + int upsample_type, tile_dimensions_type; + int temporal_step_width_modifier_signalled_flag, level1_filtering_signalled_flag; + // Skip syntax elements until we get to the custom dimension ones + temporal_step_width_modifier_signalled_flag = get_bits1(&gb); + skip_bits(&gb, 3); + upsample_type = get_bits(&gb, 3); + level1_filtering_signalled_flag = get_bits1(&gb); + skip_bits(&gb, 4); + tile_dimensions_type = get_bits(&gb, 2); + skip_bits(&gb, 4); + if (processed_planes_type_flag) + skip_bits(&gb, 4); + if (temporal_step_width_modifier_signalled_flag) + skip_bits(&gb, 8); + if (upsample_type) + skip_bits_long(&gb, 64); + if (level1_filtering_signalled_flag) + skip_bits(&gb, 8); + if (tile_dimensions_type) { + if (tile_dimensions_type == 3) + skip_bits_long(&gb, 32); + skip_bits(&gb, 8); + } + + s->width = get_bits(&gb, 16); + s->height = get_bits(&gb, 16); + } + break; + } + default: + break; + } + + bytestream2_skip(&gbc, block_size); + } + + return 0; +} + +static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, + int buf_size, AVCodecContext *avctx) +{ + LCEVCParserContext *ctx = s->priv_data; + int flags = (H2645_FLAG_IS_NALFF * !!ctx->is_lvcc) | H2645_FLAG_SMALL_PADDING; + int ret, i; + + /* set some sane default values */ + s->pict_type = AV_PICTURE_TYPE_NONE; + s->key_frame = 0; + s->picture_structure = AV_PICTURE_STRUCTURE_UNKNOWN; + + ret = ff_h2645_packet_split(&ctx->pkt, buf, buf_size, avctx, + ctx->nal_length_size, AV_CODEC_ID_LCEVC, flags); + if (ret < 0) + return ret; + + for (i = 0; i < ctx->pkt.nb_nals; i++) { + H2645NAL *nal = &ctx->pkt.nals[i]; + + switch (nal->type) { + case LCEVC_IDR_NUT: + s->key_frame = 1; + // fall-through + case LCEVC_NON_IDR_NUT: + parse_nal_unit(s, avctx, nal); + break; + default: + break; + } + } + + return 0; +} + +static int lcevc_parse(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + LCEVCParserContext *ctx = s->priv_data; + ParseContext *pc = &ctx->pc; + int next; + + if (!ctx->parsed_extradata && avctx->extradata_size > 4) { + ctx->parsed_extradata = 1; + ctx->is_lvcc = !!avctx->extradata[0]; + + if (ctx->is_lvcc) + ctx->nal_length_size = (avctx->extradata[4] >> 6) + 1; + } + + if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { + next = buf_size; + } else { + next = lcevc_find_frame_end(s, buf, buf_size); + if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + } + + parse_nal_units(s, buf, buf_size, avctx); + + *poutbuf = buf; + *poutbuf_size = buf_size; + return next; +} + +static void lcevc_parser_close(AVCodecParserContext *s) +{ + LCEVCParserContext *ctx = s->priv_data; + + ff_h2645_packet_uninit(&ctx->pkt); + + av_freep(&ctx->pc.buffer); +} + +const FFCodecParser ff_lcevc_parser = { + PARSER_CODEC_LIST(AV_CODEC_ID_LCEVC), + .priv_data_size = sizeof(LCEVCParserContext), + .parse = lcevc_parse, + .close = lcevc_parser_close, +}; diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c index 4561f6eb3d..162b96cb69 100644 --- a/libavcodec/parsers.c +++ b/libavcodec/parsers.c @@ -78,6 +78,7 @@ extern const FFCodecParser ff_ipu_parser; extern const FFCodecParser ff_jpeg2000_parser; extern const FFCodecParser ff_jpegxl_parser; extern const FFCodecParser ff_jpegxs_parser; +extern const FFCodecParser ff_lcevc_parser; extern const FFCodecParser ff_misc4_parser; extern const FFCodecParser ff_mjpeg_parser; extern const FFCodecParser ff_mlp_parser; diff --git a/libavcodec/version.h b/libavcodec/version.h index e99bd317e3..735c8b813c 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,8 +29,8 @@ #include "version_major.h" -#define LIBAVCODEC_VERSION_MINOR 26 -#define LIBAVCODEC_VERSION_MICRO 101 +#define LIBAVCODEC_VERSION_MINOR 27 +#define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
