Mercurial > libavformat.hg
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 } |