📄 avidec.c
字号:
/* * AVI demuxer * Copyright (c) 2001 Fabrice Bellard * * 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 "avformat.h"#include "avi.h"#include "dv.h"#include "riff.h"#undef NDEBUG#include <assert.h>//#define DEBUG//#define DEBUG_SEEKtypedef struct AVIStream { int64_t frame_offset; /* current frame (video) or byte (audio) counter (used to compute the pts) */ int remaining; int packet_size; int scale; int rate; int sample_size; /* size of one sample (or packet) (in the rate/scale sense) in bytes */ int64_t cum_len; /* temporary storage (used during seek) */ int prefix; ///< normally 'd'<<8 + 'c' or 'w'<<8 + 'b' int prefix_count; uint32_t pal[256]; int has_pal;} AVIStream;typedef struct { int64_t riff_end; int64_t movi_end; int64_t fsize; offset_t movi_list; int index_loaded; int is_odml; int non_interleaved; int stream_index; DVDemuxContext* dv_demux;} AVIContext;static const char avi_headers[][8] = { { 'R', 'I', 'F', 'F', 'A', 'V', 'I', ' ' }, { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 'X' }, { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 0x19}, { 'O', 'N', '2', ' ', 'O', 'N', '2', 'f' }, { 'R', 'I', 'F', 'F', 'A', 'M', 'V', ' ' }, { 0 }};static int avi_load_index(AVFormatContext *s);static int guess_ni_flag(AVFormatContext *s);#ifdef DEBUGstatic void print_tag(const char *str, unsigned int tag, int size){ printf("%s: tag=%c%c%c%c size=0x%x\n", str, tag & 0xff, (tag >> 8) & 0xff, (tag >> 16) & 0xff, (tag >> 24) & 0xff, size);}#endifstatic int get_riff(AVIContext *avi, ByteIOContext *pb){ char header[8]; int i; /* check RIFF header */#ifndef __CW32__ get_buffer(pb, header, 4);#else get_buffer(pb, (unsigned char *)header, 4);#endif avi->riff_end = get_le32(pb); /* RIFF chunk size */ avi->riff_end += url_ftell(pb); /* RIFF chunk end */#ifndef __CW32__ get_buffer(pb, header+4, 4);#else get_buffer(pb, (unsigned char *)(header+4), 4);#endif for(i=0; avi_headers[i][0]; i++) if(!memcmp(header, avi_headers[i], 8)) break; if(!avi_headers[i][0]) return -1; if(header[7] == 0x19) av_log(NULL, AV_LOG_INFO, "This file has been generated by a totally broken muxer.\n"); return 0;}static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ AVIContext *avi = s->priv_data; ByteIOContext *pb = s->pb; int longs_pre_entry= get_le16(pb); int index_sub_type = get_byte(pb); int index_type = get_byte(pb); int entries_in_use = get_le32(pb); int chunk_id = get_le32(pb); int64_t base = get_le64(pb); int stream_id= 10*((chunk_id&0xFF) - '0') + (((chunk_id>>8)&0xFF) - '0'); AVStream *st; AVIStream *ast; int i; int64_t last_pos= -1; int64_t filesize= url_fsize(s->pb);#ifdef DEBUG_SEEK av_log(s, AV_LOG_ERROR, "longs_pre_entry:%d index_type:%d entries_in_use:%d chunk_id:%X base:%16"PRIX64"\n", longs_pre_entry,index_type, entries_in_use, chunk_id, base);#endif if(stream_id > s->nb_streams || stream_id < 0) return -1; st= s->streams[stream_id]; ast = st->priv_data; if(index_sub_type) return -1; get_le32(pb); if(index_type && longs_pre_entry != 2) return -1; if(index_type>1) return -1; if(filesize > 0 && base >= filesize){ av_log(s, AV_LOG_ERROR, "ODML index invalid\n"); if(base>>32 == (base & 0xFFFFFFFF) && (base & 0xFFFFFFFF) < filesize && filesize <= 0xFFFFFFFF) base &= 0xFFFFFFFF; else return -1; } for(i=0; i<entries_in_use; i++){ if(index_type){ int64_t pos= get_le32(pb) + base - 8; int len = get_le32(pb); int key= len >= 0; len &= 0x7FFFFFFF;#ifdef DEBUG_SEEK av_log(s, AV_LOG_ERROR, "pos:%"PRId64", len:%X\n", pos, len);#endif if(last_pos == pos || pos == base - 8) avi->non_interleaved= 1; else av_add_index_entry(st, pos, ast->cum_len / FFMAX(1, ast->sample_size), len, 0, key ? AVINDEX_KEYFRAME : 0); if(ast->sample_size) ast->cum_len += len; else ast->cum_len ++; last_pos= pos; }else{ int64_t offset, pos; int duration; offset = get_le64(pb); get_le32(pb); /* size */ duration = get_le32(pb); pos = url_ftell(pb); url_fseek(pb, offset+8, SEEK_SET); read_braindead_odml_indx(s, frame_num); frame_num += duration; url_fseek(pb, pos, SEEK_SET); } } avi->index_loaded=1; return 0;}static void clean_index(AVFormatContext *s){ int i; int64_t j; for(i=0; i<s->nb_streams; i++){ AVStream *st = s->streams[i]; AVIStream *ast = st->priv_data; int n= st->nb_index_entries; int max= ast->sample_size; int64_t pos, size, ts; if(n != 1 || ast->sample_size==0) continue; while(max < 1024) max+=max; pos= st->index_entries[0].pos; size= st->index_entries[0].size; ts= st->index_entries[0].timestamp; for(j=0; j<size; j+=max){ av_add_index_entry(st, pos+j, ts + j/ast->sample_size, FFMIN(max, size-j), 0, AVINDEX_KEYFRAME); } }}static int avi_read_tag(ByteIOContext *pb, char *buf, int maxlen, unsigned int size){ offset_t i = url_ftell(pb); size += (size & 1); get_strz(pb, buf, maxlen); url_fseek(pb, i+size, SEEK_SET); return 0;}static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap){ AVIContext *avi = s->priv_data; ByteIOContext *pb = s->pb; uint32_t tag, tag1, handler; int codec_type, stream_index, frame_period, bit_rate; unsigned int size, nb_frames; int i; AVStream *st; AVIStream *ast = NULL; char str_track[4]; int avih_width=0, avih_height=0; int amv_file_format=0; avi->stream_index= -1; if (get_riff(avi, pb) < 0) return -1; avi->fsize = url_fsize(pb); if(avi->fsize<=0) avi->fsize= avi->riff_end; /* first list tag */ stream_index = -1; codec_type = -1; frame_period = 0; for(;;) { if (url_feof(pb)) goto fail; tag = get_le32(pb); size = get_le32(pb);#ifdef DEBUG print_tag("tag", tag, size);#endif switch(tag) { case MKTAG('L', 'I', 'S', 'T'): /* Ignored, except at start of video packets. */ tag1 = get_le32(pb);#ifdef DEBUG print_tag("list", tag1, 0);#endif if (tag1 == MKTAG('m', 'o', 'v', 'i')) { avi->movi_list = url_ftell(pb) - 4; if(size) avi->movi_end = avi->movi_list + size + (size & 1); else avi->movi_end = url_fsize(pb);#ifdef DEBUG printf("movi end=%"PRIx64"\n", avi->movi_end);#endif goto end_of_header; } break; case MKTAG('d', 'm', 'l', 'h'): avi->is_odml = 1; url_fskip(pb, size + (size & 1)); break; case MKTAG('a', 'm', 'v', 'h'): amv_file_format=1; case MKTAG('a', 'v', 'i', 'h'): /* AVI header */ /* using frame_period is bad idea */ frame_period = get_le32(pb); bit_rate = get_le32(pb) * 8; get_le32(pb); avi->non_interleaved |= get_le32(pb) & AVIF_MUSTUSEINDEX; url_fskip(pb, 2 * 4); get_le32(pb); get_le32(pb); avih_width=get_le32(pb); avih_height=get_le32(pb); url_fskip(pb, size - 10 * 4); break; case MKTAG('s', 't', 'r', 'h'): /* stream header */ tag1 = get_le32(pb); handler = get_le32(pb); /* codec tag */ if(tag1 == MKTAG('p', 'a', 'd', 's')){ url_fskip(pb, size - 8); break; }else{ stream_index++; st = av_new_stream(s, stream_index); if (!st) goto fail; ast = av_mallocz(sizeof(AVIStream)); if (!ast) goto fail; st->priv_data = ast; } if(amv_file_format) tag1 = stream_index ? MKTAG('a','u','d','s') : MKTAG('v','i','d','s');#ifdef DEBUG print_tag("strh", tag1, -1);#endif if(tag1 == MKTAG('i', 'a', 'v', 's') || tag1 == MKTAG('i', 'v', 'a', 's')){ int64_t dv_dur; /* * After some consideration -- I don't think we * have to support anything but DV in type1 AVIs. */ if (s->nb_streams != 1) goto fail; if (handler != MKTAG('d', 'v', 's', 'd') && handler != MKTAG('d', 'v', 'h', 'd') && handler != MKTAG('d', 'v', 's', 'l')) goto fail; ast = s->streams[0]->priv_data; av_freep(&s->streams[0]->codec->extradata); av_freep(&s->streams[0]); s->nb_streams = 0; if (ENABLE_DV_DEMUXER) { avi->dv_demux = dv_init_demux(s); if (!avi->dv_demux) goto fail; } s->streams[0]->priv_data = ast; url_fskip(pb, 3 * 4); ast->scale = get_le32(pb); ast->rate = get_le32(pb); url_fskip(pb, 4); /* start time */ dv_dur = get_le32(pb); if (ast->scale > 0 && ast->rate > 0 && dv_dur > 0) { dv_dur *= AV_TIME_BASE; s->duration = av_rescale(dv_dur, ast->scale, ast->rate);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -