You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
				
					committed by
					
						 James Almer
						James Almer
					
				
			
			
				
	
			
			
			
						parent
						
							3069a8fe3c
						
					
				
				
					commit
					ab2671c5f2
				
			| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
							
								
								
									
										170
									
								
								libavcodec/evc_frame_merge_bsf.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								libavcodec/evc_frame_merge_bsf.c
									
									
									
									
									
										Normal file
									
								
							| @@ -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, | ||||
| }; | ||||
| @@ -251,6 +251,7 @@ OBJS-$(CONFIG_HCOM_DEMUXER)              += hcom.o pcm.o | ||||
| OBJS-$(CONFIG_HDS_MUXER)                 += hdsenc.o | ||||
| OBJS-$(CONFIG_HEVC_DEMUXER)              += hevcdec.o rawdec.o | ||||
| OBJS-$(CONFIG_HEVC_MUXER)                += rawenc.o | ||||
| OBJS-$(CONFIG_EVC_DEMUXER)               += evcdec.o rawdec.o | ||||
| OBJS-$(CONFIG_EVC_MUXER)                 += rawenc.o | ||||
| OBJS-$(CONFIG_HLS_DEMUXER)               += hls.o hls_sample_encryption.o | ||||
| OBJS-$(CONFIG_HLS_MUXER)                 += hlsenc.o hlsplaylist.o avc.o | ||||
|   | ||||
| @@ -154,6 +154,7 @@ extern const AVInputFormat  ff_ea_cdata_demuxer; | ||||
| extern const AVInputFormat  ff_eac3_demuxer; | ||||
| extern const FFOutputFormat ff_eac3_muxer; | ||||
| extern const AVInputFormat  ff_epaf_demuxer; | ||||
| extern const AVInputFormat  ff_evc_demuxer; | ||||
| extern const FFOutputFormat ff_evc_muxer; | ||||
| extern const FFOutputFormat ff_f4v_muxer; | ||||
| extern const AVInputFormat  ff_ffmetadata_demuxer; | ||||
|   | ||||
							
								
								
									
										276
									
								
								libavformat/evcdec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								libavformat/evcdec.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,276 @@ | ||||
| /* | ||||
|  * RAW EVC video demuxer | ||||
|  * | ||||
|  * Copyright (c) 2021 Dawid Kozinski <d.kozinski@samsung.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 "libavcodec/get_bits.h" | ||||
| #include "libavcodec/golomb.h" | ||||
| #include "libavcodec/internal.h" | ||||
| #include "libavcodec/evc.h" | ||||
| #include "libavcodec/bsf.h" | ||||
|  | ||||
| #include "libavutil/opt.h" | ||||
|  | ||||
| #include "rawdec.h" | ||||
| #include "avformat.h" | ||||
| #include "internal.h" | ||||
|  | ||||
|  | ||||
| #define RAW_PACKET_SIZE 1024 | ||||
|  | ||||
| typedef struct EVCParserContext { | ||||
|     int got_sps; | ||||
|     int got_pps; | ||||
|     int got_idr; | ||||
|     int got_nonidr; | ||||
|  | ||||
| } EVCParserContext; | ||||
|  | ||||
| typedef struct EVCDemuxContext { | ||||
|     const AVClass *class; | ||||
|     AVRational framerate; | ||||
|  | ||||
|     AVBSFContext *bsf; | ||||
|  | ||||
| } EVCDemuxContext; | ||||
|  | ||||
| #define DEC AV_OPT_FLAG_DECODING_PARAM | ||||
| #define OFFSET(x) offsetof(EVCDemuxContext, x) | ||||
| static const AVOption evc_options[] = { | ||||
|     { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, DEC}, | ||||
|     { NULL }, | ||||
| }; | ||||
| #undef OFFSET | ||||
|  | ||||
| static const AVClass evc_demuxer_class = { | ||||
|     .class_name = "EVC Annex B demuxer", | ||||
|     .item_name  = av_default_item_name, | ||||
|     .option     = evc_options, | ||||
|     .version    = LIBAVUTIL_VERSION_INT, | ||||
| }; | ||||
|  | ||||
| static int get_nalu_type(const uint8_t *bits, int bits_size) | ||||
| { | ||||
|     int unit_type_plus1 = 0; | ||||
|  | ||||
|     if (bits_size >= EVC_NALU_HEADER_SIZE) { | ||||
|         unsigned char *p = (unsigned char *)bits; | ||||
|         // forbidden_zero_bit | ||||
|         if ((p[0] & 0x80) != 0)   // Cannot get bitstream information. Malformed bitstream. | ||||
|             return -1; | ||||
|  | ||||
|         // nal_unit_type | ||||
|         unit_type_plus1 = (p[0] >> 1) & 0x3F; | ||||
|     } | ||||
|  | ||||
|     return unit_type_plus1 - 1; | ||||
| } | ||||
|  | ||||
| static uint32_t read_nal_unit_length(const uint8_t *bits, int bits_size) | ||||
| { | ||||
|     uint32_t nalu_len = 0; | ||||
|  | ||||
|     if (bits_size >= EVC_NALU_LENGTH_PREFIX_SIZE) { | ||||
|  | ||||
|         int t = 0; | ||||
|         unsigned char *p = (unsigned char *)bits; | ||||
|  | ||||
|         for (int i = 0; i < EVC_NALU_LENGTH_PREFIX_SIZE; i++) | ||||
|             t = (t << 8) | p[i]; | ||||
|  | ||||
|         nalu_len = t; | ||||
|         if (nalu_len == 0)   // Invalid bitstream size | ||||
|             return 0; | ||||
|     } | ||||
|  | ||||
|     return nalu_len; | ||||
| } | ||||
|  | ||||
| static int parse_nal_units(const AVProbeData *p, EVCParserContext *ev) | ||||
| { | ||||
|     int nalu_type; | ||||
|     size_t nalu_size; | ||||
|     unsigned char *bits = (unsigned char *)p->buf; | ||||
|     int bytes_to_read = p->buf_size; | ||||
|  | ||||
|     while (bytes_to_read > EVC_NALU_LENGTH_PREFIX_SIZE) { | ||||
|  | ||||
|         nalu_size = read_nal_unit_length(bits, EVC_NALU_LENGTH_PREFIX_SIZE); | ||||
|         if (nalu_size == 0) break; | ||||
|  | ||||
|         bits += EVC_NALU_LENGTH_PREFIX_SIZE; | ||||
|         bytes_to_read -= EVC_NALU_LENGTH_PREFIX_SIZE; | ||||
|  | ||||
|         if(bytes_to_read < nalu_size) break; | ||||
|  | ||||
|         nalu_type = get_nalu_type(bits, bytes_to_read); | ||||
|  | ||||
|         if (nalu_type == EVC_SPS_NUT) | ||||
|             ev->got_sps++; | ||||
|         else if (nalu_type == EVC_PPS_NUT) | ||||
|             ev->got_pps++; | ||||
|         else if (nalu_type == EVC_IDR_NUT ) | ||||
|             ev->got_idr++; | ||||
|         else if (nalu_type == EVC_NOIDR_NUT) | ||||
|             ev->got_nonidr++; | ||||
|  | ||||
|         bits += nalu_size; | ||||
|         bytes_to_read -= nalu_size; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int annexb_probe(const AVProbeData *p) | ||||
| { | ||||
|     EVCParserContext ev = {0}; | ||||
|     int ret = parse_nal_units(p, &ev); | ||||
|  | ||||
|     if (ret == 0 && ev.got_sps && ev.got_pps && (ev.got_idr || ev.got_nonidr > 3)) | ||||
|         return AVPROBE_SCORE_EXTENSION + 1;  // 1 more than .mpg | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int evc_read_header(AVFormatContext *s) | ||||
| { | ||||
|     AVStream *st; | ||||
|     FFStream *sti; | ||||
|     const AVBitStreamFilter *filter = av_bsf_get_by_name("evc_frame_merge"); | ||||
|     EVCDemuxContext *c = s->priv_data; | ||||
|     int ret = 0; | ||||
|  | ||||
|     st = avformat_new_stream(s, NULL); | ||||
|     if (!st) { | ||||
|         ret = AVERROR(ENOMEM); | ||||
|         goto fail; | ||||
|     } | ||||
|     sti = ffstream(st); | ||||
|  | ||||
|     st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; | ||||
|     st->codecpar->codec_id = AV_CODEC_ID_EVC; | ||||
|  | ||||
|     // This causes sending to the parser full frames, not chunks of data | ||||
|     // The flag PARSER_FLAG_COMPLETE_FRAMES will be set in demux.c (demux.c: 1316) | ||||
|     sti->need_parsing = AVSTREAM_PARSE_HEADERS; | ||||
|  | ||||
|     st->avg_frame_rate = c->framerate; | ||||
|     st->codecpar->framerate = c->framerate; | ||||
|  | ||||
|     // taken from rawvideo demuxers | ||||
|     avpriv_set_pts_info(st, 64, 1, 1200000); | ||||
|  | ||||
|     ret = av_bsf_alloc(filter, &c->bsf); | ||||
|     if (ret < 0) | ||||
|         return ret; | ||||
|  | ||||
|     ret = avcodec_parameters_copy(c->bsf->par_in, st->codecpar); | ||||
|     if (ret < 0) | ||||
|         return ret; | ||||
|  | ||||
|     ret = av_bsf_init(c->bsf); | ||||
|     if (ret < 0) | ||||
|         return ret; | ||||
|  | ||||
| fail: | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int evc_read_packet(AVFormatContext *s, AVPacket *pkt) | ||||
| { | ||||
|     int ret; | ||||
|     int32_t nalu_size; | ||||
|     int au_end_found; | ||||
|  | ||||
|     EVCDemuxContext *const c = s->priv_data; | ||||
|  | ||||
|     int eof = avio_feof (s->pb); | ||||
|     if(eof) { | ||||
|         av_packet_unref(pkt); | ||||
|         return AVERROR_EOF; | ||||
|     } | ||||
|  | ||||
|     au_end_found = 0; | ||||
|  | ||||
|     while(!au_end_found) { | ||||
|  | ||||
|         uint8_t buf[EVC_NALU_LENGTH_PREFIX_SIZE]; | ||||
|         ret = avio_read(s->pb, (unsigned char *)&buf, EVC_NALU_LENGTH_PREFIX_SIZE); | ||||
|         if (ret < 0) { | ||||
|             av_packet_unref(pkt); | ||||
|             return ret; | ||||
|         } | ||||
|  | ||||
|         nalu_size = read_nal_unit_length((const uint8_t *)&buf, EVC_NALU_LENGTH_PREFIX_SIZE); | ||||
|         if(nalu_size <= 0) { | ||||
|             av_packet_unref(pkt); | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         avio_seek(s->pb, -EVC_NALU_LENGTH_PREFIX_SIZE, SEEK_CUR); | ||||
|  | ||||
|         ret = av_get_packet(s->pb, pkt, nalu_size + EVC_NALU_LENGTH_PREFIX_SIZE); | ||||
|         if (ret < 0) | ||||
|             return ret; | ||||
|         if (ret != (nalu_size + EVC_NALU_LENGTH_PREFIX_SIZE)) | ||||
|             return AVERROR(EIO); | ||||
|  | ||||
|         ret = av_bsf_send_packet(c->bsf, pkt); | ||||
|         if (ret < 0) { | ||||
|             av_log(s, AV_LOG_ERROR, "Failed to send packet to " | ||||
|                    "evc_frame_merge filter\n"); | ||||
|             return ret; | ||||
|         } | ||||
|  | ||||
|         ret = av_bsf_receive_packet(c->bsf, pkt); | ||||
|         if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) | ||||
|             av_log(s, AV_LOG_ERROR, "evc_frame_merge filter failed to " | ||||
|                    "send output packet\n"); | ||||
|  | ||||
|         au_end_found = 1; | ||||
|         if (ret == AVERROR(EAGAIN)) | ||||
|             au_end_found = 0; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int evc_read_close(AVFormatContext *s) | ||||
| { | ||||
|     EVCDemuxContext *const c = s->priv_data; | ||||
|  | ||||
|     av_bsf_free(&c->bsf); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| const AVInputFormat ff_evc_demuxer = { | ||||
|     .name           = "evc", | ||||
|     .long_name      = NULL_IF_CONFIG_SMALL("EVC Annex B"), | ||||
|     .read_probe     = annexb_probe, | ||||
|     .read_header    = evc_read_header, // annexb_read_header | ||||
|     .read_packet    = evc_read_packet, // annexb_read_packet | ||||
|     .read_close     = evc_read_close, | ||||
|     .extensions     = "evc", | ||||
|     .flags          = AVFMT_GENERIC_INDEX, | ||||
|     .flags_internal = FF_FMT_INIT_CLEANUP, | ||||
|     .raw_codec_id   = AV_CODEC_ID_EVC, | ||||
|     .priv_data_size = sizeof(EVCDemuxContext), | ||||
|     .priv_class     = &evc_demuxer_class, | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user