comparison sierravmd.c @ 387:f2760852ed18 libavformat

minor VMD system update; still not perfect, but should not crash either
author melanson
date Sun, 14 Mar 2004 04:08:11 +0000
parents 6f50cb0ead51
children b69898ffc92a
comparison
equal deleted inserted replaced
386:c152849ee643 387:f2760852ed18
19 19
20 /** 20 /**
21 * @file sierravmd.c 21 * @file sierravmd.c
22 * Sierra VMD file demuxer 22 * Sierra VMD file demuxer
23 * by Vladimir "VAG" Gneushev (vagsoft at mail.ru) 23 * by Vladimir "VAG" Gneushev (vagsoft at mail.ru)
24 * for more information on the Sierra VMD file format, visit:
25 * http://www.pcisys.net/~melanson/codecs/
24 */ 26 */
25 27
26 #include "avformat.h" 28 #include "avformat.h"
27
28 #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0])
29 #define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \
30 (((uint8_t*)(x))[2] << 16) | \
31 (((uint8_t*)(x))[1] << 8) | \
32 ((uint8_t*)(x))[0])
33 29
34 #define VMD_HEADER_SIZE 0x0330 30 #define VMD_HEADER_SIZE 0x0330
35 #define BYTES_PER_FRAME_RECORD 16 31 #define BYTES_PER_FRAME_RECORD 16
36 32
37 typedef struct { 33 typedef struct {
54 50
55 unsigned int frame_count; 51 unsigned int frame_count;
56 vmd_frame_t *frame_table; 52 vmd_frame_t *frame_table;
57 unsigned int current_frame; 53 unsigned int current_frame;
58 54
55 int sample_rate;
56 int64_t audio_sample_counter;
57 int audio_frame_divisor;
58 int audio_block_align;
59
59 unsigned char vmd_header[VMD_HEADER_SIZE]; 60 unsigned char vmd_header[VMD_HEADER_SIZE];
60 } VmdDemuxContext; 61 } VmdDemuxContext;
61 62
62 static int vmd_probe(AVProbeData *p) 63 static int vmd_probe(AVProbeData *p)
63 { 64 {
69 if (LE_16(&p->buf[0]) != VMD_HEADER_SIZE - 2) 70 if (LE_16(&p->buf[0]) != VMD_HEADER_SIZE - 2)
70 return 0; 71 return 0;
71 72
72 /* only return half certainty since this check is a bit sketchy */ 73 /* only return half certainty since this check is a bit sketchy */
73 return AVPROBE_SCORE_MAX / 2; 74 return AVPROBE_SCORE_MAX / 2;
75 }
76
77 /* This is a support function to determine the duration, in sample
78 * frames, of a particular audio chunk, taking into account silent
79 * encodings. */
80 static int vmd_calculate_audio_duration(unsigned char *audio_chunk,
81 int audio_chunk_size, int block_align)
82 {
83 unsigned char *p = audio_chunk + 16;
84 unsigned char *p_end = audio_chunk + audio_chunk_size;
85 int total_samples = 0;
86 unsigned int sound_flags;
87
88 if (audio_chunk_size < 16)
89 return 0;
90
91 sound_flags = LE_32(p);
92 p += 4;
93 while (p < p_end) {
94 total_samples += block_align;
95 if ((sound_flags & 0x01) == 0)
96 p += block_align;
97 sound_flags >>= 1;
98 }
99
100 return total_samples;
74 } 101 }
75 102
76 static int vmd_read_header(AVFormatContext *s, 103 static int vmd_read_header(AVFormatContext *s,
77 AVFormatParameters *ap) 104 AVFormatParameters *ap)
78 { 105 {
83 unsigned char *raw_frame_table; 110 unsigned char *raw_frame_table;
84 int raw_frame_table_size; 111 int raw_frame_table_size;
85 unsigned char *current_frame_record; 112 unsigned char *current_frame_record;
86 offset_t current_offset; 113 offset_t current_offset;
87 int i; 114 int i;
88 int sample_rate;
89 unsigned int total_frames; 115 unsigned int total_frames;
90 int video_frame_count = 0; 116 int64_t video_pts_inc;
117 int64_t current_video_pts = 0;
91 118
92 /* fetch the main header, including the 2 header length bytes */ 119 /* fetch the main header, including the 2 header length bytes */
93 url_fseek(pb, 0, SEEK_SET); 120 url_fseek(pb, 0, SEEK_SET);
94 if (get_buffer(pb, vmd->vmd_header, VMD_HEADER_SIZE) != VMD_HEADER_SIZE) 121 if (get_buffer(pb, vmd->vmd_header, VMD_HEADER_SIZE) != VMD_HEADER_SIZE)
95 return -EIO; 122 return -EIO;
123
124 vmd->audio_sample_counter = 0;
125 vmd->audio_frame_divisor = 1;
126 vmd->audio_block_align = 1;
96 127
97 /* start up the decoders */ 128 /* start up the decoders */
98 st = av_new_stream(s, 0); 129 st = av_new_stream(s, 0);
99 if (!st) 130 if (!st)
100 return AVERROR_NOMEM; 131 return AVERROR_NOMEM;
107 st->codec.extradata_size = VMD_HEADER_SIZE; 138 st->codec.extradata_size = VMD_HEADER_SIZE;
108 st->codec.extradata = av_malloc(VMD_HEADER_SIZE); 139 st->codec.extradata = av_malloc(VMD_HEADER_SIZE);
109 memcpy(st->codec.extradata, vmd->vmd_header, VMD_HEADER_SIZE); 140 memcpy(st->codec.extradata, vmd->vmd_header, VMD_HEADER_SIZE);
110 141
111 /* if sample rate is 0, assume no audio */ 142 /* if sample rate is 0, assume no audio */
112 sample_rate = LE_16(&vmd->vmd_header[804]); 143 vmd->sample_rate = LE_16(&vmd->vmd_header[804]);
113 if (sample_rate) { 144 if (vmd->sample_rate) {
114 st = av_new_stream(s, 0); 145 st = av_new_stream(s, 0);
115 if (!st) 146 if (!st)
116 return AVERROR_NOMEM; 147 return AVERROR_NOMEM;
117 vmd->audio_stream_index = st->index; 148 vmd->audio_stream_index = st->index;
118 st->codec.codec_type = CODEC_TYPE_AUDIO; 149 st->codec.codec_type = CODEC_TYPE_AUDIO;
119 st->codec.codec_id = CODEC_ID_VMDAUDIO; 150 st->codec.codec_id = CODEC_ID_VMDAUDIO;
120 st->codec.codec_tag = 0; /* no codec tag */ 151 st->codec.codec_tag = 0; /* no codec tag */
121 st->codec.channels = (vmd->vmd_header[811] & 0x80) ? 2 : 1; 152 st->codec.channels = (vmd->vmd_header[811] & 0x80) ? 2 : 1;
122 st->codec.sample_rate = sample_rate; 153 st->codec.sample_rate = vmd->sample_rate;
123 st->codec.bit_rate = st->codec.sample_rate * 154 st->codec.block_align = vmd->audio_block_align =
124 st->codec.bits_per_sample * st->codec.channels; 155 LE_16(&vmd->vmd_header[806]);
125 st->codec.block_align = LE_16(&vmd->vmd_header[806]);
126 if (st->codec.block_align & 0x8000) { 156 if (st->codec.block_align & 0x8000) {
127 st->codec.bits_per_sample = 16; 157 st->codec.bits_per_sample = 16;
128 st->codec.block_align = -(st->codec.block_align - 0x10000); 158 st->codec.block_align = -(st->codec.block_align - 0x10000);
129 } else 159 } else
130 st->codec.bits_per_sample = 8; 160 st->codec.bits_per_sample = 16;
161 // st->codec.bits_per_sample = 8;
162 st->codec.bit_rate = st->codec.sample_rate *
163 st->codec.bits_per_sample * st->codec.channels;
164
165 /* for calculating pts */
166 vmd->audio_frame_divisor = st->codec.bits_per_sample / 8 /
167 st->codec.channels;
168
169 video_pts_inc = 90000;
170 video_pts_inc *= st->codec.block_align;
171 video_pts_inc /= st->codec.sample_rate;
172 } else {
173 /* if no audio, assume 10 frames/second */
174 video_pts_inc = 90000 / 10;
131 } 175 }
132 176
133 /* skip over the offset table and load the table of contents; don't 177 /* skip over the offset table and load the table of contents; don't
134 * care about the offset table since demuxer will calculate those 178 * care about the offset table since demuxer will calculate those
135 * independently */ 179 * independently */
182 vmd->frame_table[i].frame_offset = current_offset; 226 vmd->frame_table[i].frame_offset = current_offset;
183 current_offset += vmd->frame_table[i].frame_size; 227 current_offset += vmd->frame_table[i].frame_size;
184 memcpy(vmd->frame_table[i].frame_record, current_frame_record, 228 memcpy(vmd->frame_table[i].frame_record, current_frame_record,
185 BYTES_PER_FRAME_RECORD); 229 BYTES_PER_FRAME_RECORD);
186 230
187 if (current_frame_record[0] == 0x02) { 231 /* figure out the pts for this frame */
188 /* assume 15 fps for now */ 232 if (current_frame_record[0] == 0x02) {
189 vmd->frame_table[i].pts = video_frame_count++; 233 vmd->frame_table[i].pts = current_video_pts;
190 vmd->frame_table[i].pts *= 90000; 234 current_video_pts += video_pts_inc;
191 vmd->frame_table[i].pts /= 15; 235 } else if (current_frame_record[0] == 0x01) {
192 } 236 /* figure out the pts during the dispatch phase */
237 vmd->frame_table[i].pts = 0;
238 }
193 239
194 current_frame_record += BYTES_PER_FRAME_RECORD; 240 current_frame_record += BYTES_PER_FRAME_RECORD;
195 i++; 241 i++;
196 } 242 }
197 243
225 return AVERROR_NOMEM; 271 return AVERROR_NOMEM;
226 memcpy(pkt->data, frame->frame_record, BYTES_PER_FRAME_RECORD); 272 memcpy(pkt->data, frame->frame_record, BYTES_PER_FRAME_RECORD);
227 ret = get_buffer(pb, pkt->data + BYTES_PER_FRAME_RECORD, 273 ret = get_buffer(pb, pkt->data + BYTES_PER_FRAME_RECORD,
228 frame->frame_size); 274 frame->frame_size);
229 275
230 if (ret != frame->frame_size) 276 if (ret != frame->frame_size) {
277 av_free_packet(pkt);
231 ret = -EIO; 278 ret = -EIO;
279 }
232 pkt->stream_index = frame->stream_index; 280 pkt->stream_index = frame->stream_index;
233 pkt->pts = frame->pts; 281 if (frame->frame_record[0] == 0x02)
282 pkt->pts = frame->pts;
283 else {
284 pkt->pts = vmd->audio_sample_counter;
285 pkt->pts *= 90000;
286 pkt->pts /= vmd->sample_rate;
287 // pkt->pts /= vmd->audio_frame_divisor;
288 vmd->audio_sample_counter += vmd_calculate_audio_duration(
289 pkt->data, pkt->size, vmd->audio_block_align);
290
291 }
292 printf (" dispatching %s frame with %d bytes and pts %lld (%0.1f sec)\n",
293 (frame->frame_record[0] == 0x02) ? "video" : "audio",
294 frame->frame_size + BYTES_PER_FRAME_RECORD,
295 pkt->pts, (float)(pkt->pts / 90000.0));
234 296
235 vmd->current_frame++; 297 vmd->current_frame++;
236 298
237 return ret; 299 return ret;
238 } 300 }