Libav
|
00001 /* 00002 * Sierra VMD Format Demuxer 00003 * Copyright (c) 2004 The ffmpeg Project 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00030 #include "libavutil/intreadwrite.h" 00031 #include "avformat.h" 00032 00033 #define VMD_HEADER_SIZE 0x0330 00034 #define BYTES_PER_FRAME_RECORD 16 00035 00036 typedef struct { 00037 int stream_index; 00038 int64_t frame_offset; 00039 unsigned int frame_size; 00040 int64_t pts; 00041 int keyframe; 00042 unsigned char frame_record[BYTES_PER_FRAME_RECORD]; 00043 } vmd_frame; 00044 00045 typedef struct VmdDemuxContext { 00046 int video_stream_index; 00047 int audio_stream_index; 00048 00049 unsigned int frame_count; 00050 unsigned int frames_per_block; 00051 vmd_frame *frame_table; 00052 unsigned int current_frame; 00053 int is_indeo3; 00054 00055 int sample_rate; 00056 int64_t audio_sample_counter; 00057 int skiphdr; 00058 00059 unsigned char vmd_header[VMD_HEADER_SIZE]; 00060 } VmdDemuxContext; 00061 00062 static int vmd_probe(AVProbeData *p) 00063 { 00064 int w, h; 00065 if (p->buf_size < 16) 00066 return 0; 00067 /* check if the first 2 bytes of the file contain the appropriate size 00068 * of a VMD header chunk */ 00069 if (AV_RL16(&p->buf[0]) != VMD_HEADER_SIZE - 2) 00070 return 0; 00071 w = AV_RL16(&p->buf[12]); 00072 h = AV_RL16(&p->buf[14]); 00073 if (!w || w > 2048 || !h || h > 2048) 00074 return 0; 00075 00076 /* only return half certainty since this check is a bit sketchy */ 00077 return AVPROBE_SCORE_MAX / 2; 00078 } 00079 00080 static int vmd_read_header(AVFormatContext *s, 00081 AVFormatParameters *ap) 00082 { 00083 VmdDemuxContext *vmd = s->priv_data; 00084 ByteIOContext *pb = s->pb; 00085 AVStream *st = NULL, *vst; 00086 unsigned int toc_offset; 00087 unsigned char *raw_frame_table; 00088 int raw_frame_table_size; 00089 int64_t current_offset; 00090 int i, j; 00091 unsigned int total_frames; 00092 int64_t current_audio_pts = 0; 00093 unsigned char chunk[BYTES_PER_FRAME_RECORD]; 00094 int num, den; 00095 int sound_buffers; 00096 00097 /* fetch the main header, including the 2 header length bytes */ 00098 url_fseek(pb, 0, SEEK_SET); 00099 if (get_buffer(pb, vmd->vmd_header, VMD_HEADER_SIZE) != VMD_HEADER_SIZE) 00100 return AVERROR(EIO); 00101 00102 if(vmd->vmd_header[16] == 'i' && vmd->vmd_header[17] == 'v' && vmd->vmd_header[18] == '3') 00103 vmd->is_indeo3 = 1; 00104 else 00105 vmd->is_indeo3 = 0; 00106 /* start up the decoders */ 00107 vst = av_new_stream(s, 0); 00108 if (!vst) 00109 return AVERROR(ENOMEM); 00110 av_set_pts_info(vst, 33, 1, 10); 00111 vmd->video_stream_index = vst->index; 00112 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; 00113 vst->codec->codec_id = vmd->is_indeo3 ? CODEC_ID_INDEO3 : CODEC_ID_VMDVIDEO; 00114 vst->codec->codec_tag = 0; /* no fourcc */ 00115 vst->codec->width = AV_RL16(&vmd->vmd_header[12]); 00116 vst->codec->height = AV_RL16(&vmd->vmd_header[14]); 00117 if(vmd->is_indeo3 && vst->codec->width > 320){ 00118 vst->codec->width >>= 1; 00119 vst->codec->height >>= 1; 00120 } 00121 vst->codec->extradata_size = VMD_HEADER_SIZE; 00122 vst->codec->extradata = av_mallocz(VMD_HEADER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); 00123 memcpy(vst->codec->extradata, vmd->vmd_header, VMD_HEADER_SIZE); 00124 00125 /* if sample rate is 0, assume no audio */ 00126 vmd->sample_rate = AV_RL16(&vmd->vmd_header[804]); 00127 if (vmd->sample_rate) { 00128 st = av_new_stream(s, 0); 00129 if (!st) 00130 return AVERROR(ENOMEM); 00131 vmd->audio_stream_index = st->index; 00132 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00133 st->codec->codec_id = CODEC_ID_VMDAUDIO; 00134 st->codec->codec_tag = 0; /* no fourcc */ 00135 st->codec->channels = (vmd->vmd_header[811] & 0x80) ? 2 : 1; 00136 st->codec->sample_rate = vmd->sample_rate; 00137 st->codec->block_align = AV_RL16(&vmd->vmd_header[806]); 00138 if (st->codec->block_align & 0x8000) { 00139 st->codec->bits_per_coded_sample = 16; 00140 st->codec->block_align = -(st->codec->block_align - 0x10000); 00141 } else { 00142 st->codec->bits_per_coded_sample = 8; 00143 } 00144 st->codec->bit_rate = st->codec->sample_rate * 00145 st->codec->bits_per_coded_sample * st->codec->channels; 00146 00147 /* calculate pts */ 00148 num = st->codec->block_align; 00149 den = st->codec->sample_rate * st->codec->channels; 00150 av_reduce(&den, &num, den, num, (1UL<<31)-1); 00151 av_set_pts_info(vst, 33, num, den); 00152 av_set_pts_info(st, 33, num, den); 00153 } 00154 00155 toc_offset = AV_RL32(&vmd->vmd_header[812]); 00156 vmd->frame_count = AV_RL16(&vmd->vmd_header[6]); 00157 vmd->frames_per_block = AV_RL16(&vmd->vmd_header[18]); 00158 url_fseek(pb, toc_offset, SEEK_SET); 00159 00160 raw_frame_table = NULL; 00161 vmd->frame_table = NULL; 00162 sound_buffers = AV_RL16(&vmd->vmd_header[808]); 00163 raw_frame_table_size = vmd->frame_count * 6; 00164 if(vmd->frame_count * vmd->frames_per_block >= UINT_MAX / sizeof(vmd_frame) - sound_buffers){ 00165 av_log(s, AV_LOG_ERROR, "vmd->frame_count * vmd->frames_per_block too large\n"); 00166 return -1; 00167 } 00168 raw_frame_table = av_malloc(raw_frame_table_size); 00169 vmd->frame_table = av_malloc((vmd->frame_count * vmd->frames_per_block + sound_buffers) * sizeof(vmd_frame)); 00170 if (!raw_frame_table || !vmd->frame_table) { 00171 av_free(raw_frame_table); 00172 av_free(vmd->frame_table); 00173 return AVERROR(ENOMEM); 00174 } 00175 if (get_buffer(pb, raw_frame_table, raw_frame_table_size) != 00176 raw_frame_table_size) { 00177 av_free(raw_frame_table); 00178 av_free(vmd->frame_table); 00179 return AVERROR(EIO); 00180 } 00181 00182 total_frames = 0; 00183 for (i = 0; i < vmd->frame_count; i++) { 00184 00185 current_offset = AV_RL32(&raw_frame_table[6 * i + 2]); 00186 00187 /* handle each entry in index block */ 00188 for (j = 0; j < vmd->frames_per_block; j++) { 00189 int type; 00190 uint32_t size; 00191 00192 get_buffer(pb, chunk, BYTES_PER_FRAME_RECORD); 00193 type = chunk[0]; 00194 size = AV_RL32(&chunk[2]); 00195 if(!size && type != 1) 00196 continue; 00197 switch(type) { 00198 case 1: /* Audio Chunk */ 00199 if (!st) break; 00200 /* first audio chunk contains several audio buffers */ 00201 vmd->frame_table[total_frames].frame_offset = current_offset; 00202 vmd->frame_table[total_frames].stream_index = vmd->audio_stream_index; 00203 vmd->frame_table[total_frames].frame_size = size; 00204 memcpy(vmd->frame_table[total_frames].frame_record, chunk, BYTES_PER_FRAME_RECORD); 00205 vmd->frame_table[total_frames].pts = current_audio_pts; 00206 total_frames++; 00207 if(!current_audio_pts) 00208 current_audio_pts += sound_buffers; 00209 else 00210 current_audio_pts++; 00211 break; 00212 case 2: /* Video Chunk */ 00213 vmd->frame_table[total_frames].frame_offset = current_offset; 00214 vmd->frame_table[total_frames].stream_index = vmd->video_stream_index; 00215 vmd->frame_table[total_frames].frame_size = size; 00216 memcpy(vmd->frame_table[total_frames].frame_record, chunk, BYTES_PER_FRAME_RECORD); 00217 vmd->frame_table[total_frames].pts = i; 00218 total_frames++; 00219 break; 00220 } 00221 current_offset += size; 00222 } 00223 } 00224 00225 av_free(raw_frame_table); 00226 00227 vmd->current_frame = 0; 00228 vmd->frame_count = total_frames; 00229 00230 return 0; 00231 } 00232 00233 static int vmd_read_packet(AVFormatContext *s, 00234 AVPacket *pkt) 00235 { 00236 VmdDemuxContext *vmd = s->priv_data; 00237 ByteIOContext *pb = s->pb; 00238 int ret = 0; 00239 vmd_frame *frame; 00240 00241 if (vmd->current_frame >= vmd->frame_count) 00242 return AVERROR(EIO); 00243 00244 frame = &vmd->frame_table[vmd->current_frame]; 00245 /* position the stream (will probably be there already) */ 00246 url_fseek(pb, frame->frame_offset, SEEK_SET); 00247 00248 if (av_new_packet(pkt, frame->frame_size + BYTES_PER_FRAME_RECORD)) 00249 return AVERROR(ENOMEM); 00250 pkt->pos= url_ftell(pb); 00251 memcpy(pkt->data, frame->frame_record, BYTES_PER_FRAME_RECORD); 00252 if(vmd->is_indeo3) 00253 ret = get_buffer(pb, pkt->data, frame->frame_size); 00254 else 00255 ret = get_buffer(pb, pkt->data + BYTES_PER_FRAME_RECORD, 00256 frame->frame_size); 00257 00258 if (ret != frame->frame_size) { 00259 av_free_packet(pkt); 00260 ret = AVERROR(EIO); 00261 } 00262 pkt->stream_index = frame->stream_index; 00263 pkt->pts = frame->pts; 00264 av_log(s, AV_LOG_DEBUG, " dispatching %s frame with %d bytes and pts %"PRId64"\n", 00265 (frame->frame_record[0] == 0x02) ? "video" : "audio", 00266 frame->frame_size + BYTES_PER_FRAME_RECORD, 00267 pkt->pts); 00268 00269 vmd->current_frame++; 00270 00271 return ret; 00272 } 00273 00274 static int vmd_read_close(AVFormatContext *s) 00275 { 00276 VmdDemuxContext *vmd = s->priv_data; 00277 00278 av_free(vmd->frame_table); 00279 00280 return 0; 00281 } 00282 00283 AVInputFormat vmd_demuxer = { 00284 "vmd", 00285 NULL_IF_CONFIG_SMALL("Sierra VMD format"), 00286 sizeof(VmdDemuxContext), 00287 vmd_probe, 00288 vmd_read_header, 00289 vmd_read_packet, 00290 vmd_read_close, 00291 };