📄 avidec.c
字号:
/* * AVI decoder. * Copyright (c) 2001 Fabrice Bellard. * * This library 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 of the License, or (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "avformat.h"#include "avi.h"#include "dv.h"//#define DEBUG//#define DEBUG_SEEKtypedef struct AVIIndexEntry { unsigned int flags; unsigned int pos; unsigned int cum_len; /* sum of all lengths before this packet */} AVIIndexEntry;typedef struct AVIStream { AVIIndexEntry *index_entries; int nb_index_entries; int index_entries_allocated_size; int frame_offset; /* current frame (video) or byte (audio) counter (used to compute the pts) */ int scale; int rate; int sample_size; /* audio only data */ int start; int new_frame_offset; /* temporary storage (used during seek) */ int cum_len; /* temporary storage (used during seek) */} AVIStream;typedef struct { int64_t riff_end; int64_t movi_end; offset_t movi_list; int index_loaded; DVDemuxContext* dv_demux;} AVIContext;static int avi_load_index(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){ uint32_t tag; /* check RIFF header */ tag = get_le32(pb); if (tag != MKTAG('R', 'I', 'F', 'F')) return -1; avi->riff_end = get_le32(pb); /* RIFF chunk size */ avi->riff_end += url_ftell(pb); /* RIFF chunk end */ tag = get_le32(pb); if (tag != MKTAG('A', 'V', 'I', ' ') && tag != MKTAG('A', 'V', 'I', 'X')) return -1; 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, scale, rate; unsigned int size, nb_frames; int i, n; AVStream *st; AVIStream *ast; int xan_video = 0; /* hack to support Xan A/V */ if (get_riff(avi, pb) < 0) return -1; /* 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 when 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; avi->movi_end = avi->movi_list + size;#ifdef DEBUG printf("movi end=%Lx\n", avi->movi_end);#endif goto end_of_header; } break; 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; url_fskip(pb, 4 * 4); n = get_le32(pb); for(i=0;i<n;i++) { AVIStream *ast; st = av_new_stream(s, i); if (!st) goto fail; ast = av_mallocz(sizeof(AVIStream)); if (!ast) goto fail; st->priv_data = ast; } url_fskip(pb, size - 7 * 4); break; case MKTAG('s', 't', 'r', 'h'): /* stream header */ stream_index++; tag1 = get_le32(pb); handler = get_le32(pb); /* codec tag */#ifdef DEBUG print_tag("strh", tag1, -1);#endif switch(tag1) { case MKTAG('i', 'a', 'v', 's'): case MKTAG('i', 'v', 'a', 's'): /* * After some consideration -- I don't think we * have to support anything but DV in a 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; av_freep(&s->streams[0]->codec.extradata); av_freep(&s->streams[0]); s->nb_streams = 0; avi->dv_demux = dv_init_demux(s); if (!avi->dv_demux) goto fail; stream_index = s->nb_streams - 1; url_fskip(pb, size - 8); break; case MKTAG('v', 'i', 'd', 's'): codec_type = CODEC_TYPE_VIDEO; if (stream_index >= s->nb_streams) { url_fskip(pb, size - 8); break; } st = s->streams[stream_index]; ast = st->priv_data; st->codec.stream_codec_tag= handler; get_le32(pb); /* flags */ get_le16(pb); /* priority */ get_le16(pb); /* language */ get_le32(pb); /* XXX: initial frame ? */ scale = get_le32(pb); /* scale */ rate = get_le32(pb); /* rate */ if(scale && rate){ }else if(frame_period){ rate = 1000000; scale = frame_period; }else{ rate = 25; scale = 1; } ast->rate = rate; ast->scale = scale; av_set_pts_info(st, 64, scale, rate); st->codec.frame_rate = rate; st->codec.frame_rate_base = scale; get_le32(pb); /* start */ nb_frames = get_le32(pb); st->start_time = 0; st->duration = av_rescale(nb_frames, st->codec.frame_rate_base * AV_TIME_BASE, st->codec.frame_rate); url_fskip(pb, size - 9 * 4); break; case MKTAG('a', 'u', 'd', 's'): { unsigned int length; codec_type = CODEC_TYPE_AUDIO; if (stream_index >= s->nb_streams) { url_fskip(pb, size - 8); break; } st = s->streams[stream_index]; ast = st->priv_data; get_le32(pb); /* flags */ get_le16(pb); /* priority */ get_le16(pb); /* language */ get_le32(pb); /* initial frame */ ast->scale = get_le32(pb); /* scale */ ast->rate = get_le32(pb); av_set_pts_info(st, 64, ast->scale, ast->rate); ast->start= get_le32(pb); /* start */ length = get_le32(pb); /* length, in samples or bytes */ get_le32(pb); /* buffer size */ get_le32(pb); /* quality */ ast->sample_size = get_le32(pb); /* sample ssize *///av_log(NULL, AV_LOG_DEBUG, "%d %d %d %d\n", ast->scale, ast->rate, ast->sample_size, ast->start); st->start_time = 0; if (ast->rate != 0) st->duration = (int64_t)length * AV_TIME_BASE / ast->rate; url_fskip(pb, size - 12 * 4); } break; case MKTAG('t', 'x', 't', 's'): //FIXME codec_type = CODEC_TYPE_DATA; //CODEC_TYPE_SUB ? FIXME url_fskip(pb, size - 8); break; default: goto fail; } break; case MKTAG('s', 't', 'r', 'f'): /* stream header */ if (stream_index >= s->nb_streams || avi->dv_demux) { url_fskip(pb, size); } else { st = s->streams[stream_index]; switch(codec_type) { case CODEC_TYPE_VIDEO: get_le32(pb); /* size */ st->codec.width = get_le32(pb); st->codec.height = get_le32(pb); get_le16(pb); /* panes */ st->codec.bits_per_sample= get_le16(pb); /* depth */ tag1 = get_le32(pb); get_le32(pb); /* ImageSize */ get_le32(pb); /* XPelsPerMeter */ get_le32(pb); /* YPelsPerMeter */ get_le32(pb); /* ClrUsed */ get_le32(pb); /* ClrImportant */ st->codec.extradata_size= size - 10*4; st->codec.extradata= av_malloc(st->codec.extradata_size); get_buffer(pb, st->codec.extradata, st->codec.extradata_size); if(st->codec.extradata_size & 1) //FIXME check if the encoder really did this correctly get_byte(pb); /* Extract palette from extradata if bpp <= 8 */ /* This code assumes that extradata contains only palette */ /* This is true for all paletted codecs implemented in ffmpeg */ if (st->codec.extradata_size && (st->codec.bits_per_sample <= 8)) { st->codec.palctrl = av_mallocz(sizeof(AVPaletteControl));#ifdef WORDS_BIGENDIAN for (i = 0; i < FFMIN(st->codec.extradata_size, AVPALETTE_SIZE)/4; i++) st->codec.palctrl->palette[i] = bswap_32(((uint32_t*)st->codec.extradata)[i]);#else memcpy(st->codec.palctrl->palette, st->codec.extradata, FFMIN(st->codec.extradata_size, AVPALETTE_SIZE));#endif st->codec.palctrl->palette_changed = 1; }#ifdef DEBUG print_tag("video", tag1, 0);#endif st->codec.codec_type = CODEC_TYPE_VIDEO; st->codec.codec_tag = tag1; st->codec.codec_id = codec_get_id(codec_bmp_tags, tag1); if (st->codec.codec_id == CODEC_ID_XAN_WC4) xan_video = 1;// url_fskip(pb, size - 5 * 4); break; case CODEC_TYPE_AUDIO: get_wav_header(pb, &st->codec, size); if (size%2) /* 2-aligned (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */ url_fskip(pb, 1); /* special case time: To support Xan DPCM, hardcode * the format if Xxan is the video codec */ st->need_parsing = 1; /* force parsing as several audio frames can be in one packet */ if (xan_video) st->codec.codec_id = CODEC_ID_XAN_DPCM; break; default: st->codec.codec_type = CODEC_TYPE_DATA; st->codec.codec_id= CODEC_ID_NONE; st->codec.codec_tag= 0; url_fskip(pb, size); break; } } break; default: /* skip tag */ size += (size & 1); url_fskip(pb, size); break; } } end_of_header: /* check stream number */ if (stream_index != s->nb_streams - 1) { fail: for(i=0;i<s->nb_streams;i++) { av_freep(&s->streams[i]->codec.extradata); av_freep(&s->streams[i]); } return -1; } assert(!avi->index_loaded); avi_load_index(s); avi->index_loaded = 1; return 0;}static int avi_read_packet(AVFormatContext *s, AVPacket *pkt){ AVIContext *avi = s->priv_data; ByteIOContext *pb = &s->pb; int n, d[8], size, i; void* dstr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -