diff options
author | Dawid Kozinski <d.kozinski@samsung.com> | 2023-06-15 13:47:26 +0200 |
---|---|---|
committer | James Almer <jamrial@gmail.com> | 2023-06-15 09:57:35 -0300 |
commit | ab2671c5f2396864fa8da2ebae0b2a5aa942167f (patch) | |
tree | 4a29ea2ff95c171430aa79a5d139d8eb64d14f55 /libavcodec | |
parent | 3069a8fe3cc7159dceec29130deb101edf99b456 (diff) | |
download | ffmpeg-ab2671c5f2396864fa8da2ebae0b2a5aa942167f.tar.gz |
avformat/evc_demuxer: Added demuxer to handle reading EVC video files
- Provided AVInputFormat struct describing EVC input format (ff_evc_demuxer)
Signed-off-by: Dawid Kozinski <d.kozinski@samsung.com>
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/Makefile | 1 | ||||
-rw-r--r-- | libavcodec/bitstream_filters.c | 5 | ||||
-rw-r--r-- | libavcodec/evc_frame_merge_bsf.c | 170 |
3 files changed, 174 insertions, 2 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile index a28919992a..0ce8fe5b9c 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1258,6 +1258,7 @@ OBJS-$(CONFIG_VP9_METADATA_BSF) += vp9_metadata_bsf.o OBJS-$(CONFIG_VP9_RAW_REORDER_BSF) += vp9_raw_reorder_bsf.o OBJS-$(CONFIG_VP9_SUPERFRAME_BSF) += vp9_superframe_bsf.o OBJS-$(CONFIG_VP9_SUPERFRAME_SPLIT_BSF) += vp9_superframe_split_bsf.o +OBJS-$(CONFIG_EVC_FRAME_MERGE_BSF) += evc_frame_merge_bsf.o # thread libraries OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c index e8216819ca..7512fccc78 100644 --- a/libavcodec/bitstream_filters.c +++ b/libavcodec/bitstream_filters.c @@ -65,16 +65,17 @@ extern const FFBitStreamFilter ff_vp9_metadata_bsf; extern const FFBitStreamFilter ff_vp9_raw_reorder_bsf; extern const FFBitStreamFilter ff_vp9_superframe_bsf; extern const FFBitStreamFilter ff_vp9_superframe_split_bsf; +extern const FFBitStreamFilter ff_evc_frame_merge_bsf; #include "libavcodec/bsf_list.c" const AVBitStreamFilter *av_bsf_iterate(void **opaque) { - uintptr_t i = (uintptr_t)*opaque; + uintptr_t i = (uintptr_t) * opaque; const FFBitStreamFilter *f = bitstream_filters[i]; if (f) { - *opaque = (void*)(i + 1); + *opaque = (void *)(i + 1); return &f->p; } return NULL; diff --git a/libavcodec/evc_frame_merge_bsf.c b/libavcodec/evc_frame_merge_bsf.c new file mode 100644 index 0000000000..d2746a1ef6 --- /dev/null +++ b/libavcodec/evc_frame_merge_bsf.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2019 James Almer <jamrial@gmail.com> + * + * 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 "get_bits.h" +#include "golomb.h" +#include "bsf.h" +#include "bsf_internal.h" +#include "avcodec.h" + +#include "evc.h" +#include "evc_parse.h" + +#define INIT_AU_BUF_CAPACITY 1024 + +// Access unit data +typedef struct AccessUnitBuffer { + uint8_t *data; // the data buffer + size_t data_size; // size of data in bytes + size_t capacity; // buffer capacity +} AccessUnitBuffer; + +typedef struct EVCFMergeContext { + AVPacket *in; + EVCParserContext parser_ctx; + AccessUnitBuffer au_buffer; +} EVCFMergeContext; + +static int end_of_access_unit_found(EVCParserContext *parser_ctx) +{ + if (parser_ctx->profile == 0) { // BASELINE profile + if (parser_ctx->nalu_type == EVC_NOIDR_NUT || parser_ctx->nalu_type == EVC_IDR_NUT) + return 1; + } else { // MAIN profile + if (parser_ctx->nalu_type == EVC_NOIDR_NUT) { + if (parser_ctx->poc.PicOrderCntVal != parser_ctx->poc.prevPicOrderCntVal) + return 1; + } else if (parser_ctx->nalu_type == EVC_IDR_NUT) + return 1; + } + return 0; +} + +static void evc_frame_merge_flush(AVBSFContext *bsf) +{ + EVCFMergeContext *ctx = bsf->priv_data; + + av_packet_unref(ctx->in); +} + +static int evc_frame_merge_filter(AVBSFContext *bsf, AVPacket *out) +{ + EVCFMergeContext *ctx = bsf->priv_data; + EVCParserContext *parser_ctx = &ctx->parser_ctx; + + AVPacket *in = ctx->in; + + int free_space = 0; + size_t nalu_size = 0; + uint8_t *nalu = NULL; + int au_end_found = 0; + int err; + + err = ff_bsf_get_packet_ref(bsf, in); + if (err < 0) + return err; + + nalu_size = evc_read_nal_unit_length(in->data, EVC_NALU_LENGTH_PREFIX_SIZE, bsf); + if (nalu_size <= 0) { + av_packet_unref(in); + return AVERROR_INVALIDDATA; + } + + nalu = in->data + EVC_NALU_LENGTH_PREFIX_SIZE; + nalu_size = in->size - EVC_NALU_LENGTH_PREFIX_SIZE; + + // NAL unit parsing needed to determine if end of AU was found + err = ff_evc_parse_nal_unit(parser_ctx, nalu, nalu_size, bsf); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "NAL Unit parsing error\n"); + av_packet_unref(in); + + return err; + } + + au_end_found = end_of_access_unit_found(parser_ctx); + + free_space = ctx->au_buffer.capacity - ctx->au_buffer.data_size; + while (free_space < in->size) { + ctx->au_buffer.capacity *= 2; + free_space = ctx->au_buffer.capacity - ctx->au_buffer.data_size; + + if (free_space >= in->size) + ctx->au_buffer.data = av_realloc(ctx->au_buffer.data, ctx->au_buffer.capacity); + } + + memcpy(ctx->au_buffer.data + ctx->au_buffer.data_size, in->data, in->size); + + ctx->au_buffer.data_size += in->size; + + av_packet_unref(in); + + if (au_end_found) { + uint8_t *data = av_memdup(ctx->au_buffer.data, ctx->au_buffer.data_size); + err = av_packet_from_data(out, data, ctx->au_buffer.data_size); + + ctx->au_buffer.data_size = 0; + } else + err = AVERROR(EAGAIN); + + if (err < 0 && err != AVERROR(EAGAIN)) + evc_frame_merge_flush(bsf); + + return err; +} + +static int evc_frame_merge_init(AVBSFContext *bsf) +{ + EVCFMergeContext *ctx = bsf->priv_data; + + ctx->in = av_packet_alloc(); + if (!ctx->in) + return AVERROR(ENOMEM); + + ctx->au_buffer.capacity = INIT_AU_BUF_CAPACITY; + ctx->au_buffer.data = av_malloc(INIT_AU_BUF_CAPACITY); + ctx->au_buffer.data_size = 0; + + return 0; +} + +static void evc_frame_merge_close(AVBSFContext *bsf) +{ + EVCFMergeContext *ctx = bsf->priv_data; + + av_packet_free(&ctx->in); + + ctx->au_buffer.capacity = 0; + av_freep(&ctx->au_buffer.data); + ctx->au_buffer.data_size = 0; +} + +static const enum AVCodecID evc_frame_merge_codec_ids[] = { + AV_CODEC_ID_EVC, AV_CODEC_ID_NONE, +}; + +const FFBitStreamFilter ff_evc_frame_merge_bsf = { + .p.name = "evc_frame_merge", + .p.codec_ids = evc_frame_merge_codec_ids, + .priv_data_size = sizeof(EVCFMergeContext), + .init = evc_frame_merge_init, + .flush = evc_frame_merge_flush, + .close = evc_frame_merge_close, + .filter = evc_frame_merge_filter, +}; |