Mercurial > libavformat.hg
annotate voc.c @ 1485:9000f9cdac49 libavformat
fix checksum check (was my bug not libnut)
author | michael |
---|---|
date | Sun, 12 Nov 2006 12:16:59 +0000 |
parents | 0899bfe4105c |
children |
rev | line source |
---|---|
937 | 1 /* |
2 * Creative Voice File demuxer. | |
3 * Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org> | |
4 * | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1172
diff
changeset
|
5 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1172
diff
changeset
|
6 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1172
diff
changeset
|
7 * FFmpeg is free software; you can redistribute it and/or |
937 | 8 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1172
diff
changeset
|
10 * version 2.1 of the License, or (at your option) any later version. |
937 | 11 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1172
diff
changeset
|
12 * FFmpeg is distributed in the hope that it will be useful, |
937 | 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1172
diff
changeset
|
18 * License along with FFmpeg; if not, write to the Free Software |
937 | 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
20 */ | |
21 | |
22 #include "avformat.h" | |
1172
6a5e58d2114b
move common stuff from avienc.c and wav.c to new file riff.c
mru
parents:
1169
diff
changeset
|
23 #include "riff.h" /* for CodecTag */ |
937 | 24 #include "voc.h" |
25 | |
26 | |
27 typedef enum voc_type { | |
28 VOC_TYPE_EOF = 0x00, | |
29 VOC_TYPE_VOICE_DATA = 0x01, | |
30 VOC_TYPE_VOICE_DATA_CONT = 0x02, | |
31 VOC_TYPE_SILENCE = 0x03, | |
32 VOC_TYPE_MARKER = 0x04, | |
33 VOC_TYPE_ASCII = 0x05, | |
34 VOC_TYPE_REPETITION_START = 0x06, | |
35 VOC_TYPE_REPETITION_END = 0x07, | |
36 VOC_TYPE_EXTENDED = 0x08, | |
37 VOC_TYPE_NEW_VOICE_DATA = 0x09, | |
38 } voc_type_t; | |
39 | |
40 | |
41 static const int voc_max_pkt_size = 2048; | |
42 static const unsigned char voc_magic[] = "Creative Voice File\x1A"; | |
43 | |
44 static const CodecTag voc_codec_tags[] = { | |
45 {CODEC_ID_PCM_U8, 0x00}, | |
960 | 46 {CODEC_ID_ADPCM_SBPRO_4, 0x01}, |
47 {CODEC_ID_ADPCM_SBPRO_3, 0x02}, | |
48 {CODEC_ID_ADPCM_SBPRO_2, 0x03}, | |
937 | 49 {CODEC_ID_PCM_S16LE, 0x04}, |
50 {CODEC_ID_PCM_ALAW, 0x06}, | |
51 {CODEC_ID_PCM_MULAW, 0x07}, | |
52 {CODEC_ID_ADPCM_CT, 0x0200}, | |
53 {0, 0}, | |
54 }; | |
55 | |
56 | |
57 #ifdef CONFIG_DEMUXERS | |
58 | |
59 static int voc_probe(AVProbeData *p) | |
60 { | |
61 int version, check; | |
62 | |
63 if (p->buf_size < 26) | |
64 return 0; | |
65 if (memcmp(p->buf, voc_magic, sizeof(voc_magic) - 1)) | |
66 return 0; | |
67 version = p->buf[22] | (p->buf[23] << 8); | |
68 check = p->buf[24] | (p->buf[25] << 8); | |
69 if (~version + 0x1234 != check) | |
70 return 10; | |
71 | |
72 return AVPROBE_SCORE_MAX; | |
73 } | |
74 | |
75 static int voc_read_header(AVFormatContext *s, AVFormatParameters *ap) | |
76 { | |
77 voc_dec_context_t *voc = s->priv_data; | |
78 ByteIOContext *pb = &s->pb; | |
79 int header_size; | |
80 AVStream *st; | |
81 | |
82 url_fskip(pb, 20); | |
83 header_size = get_le16(pb) - 22; | |
84 if (header_size != 4) { | |
85 av_log(s, AV_LOG_ERROR, "unkown header size: %d\n", header_size); | |
86 return AVERROR_NOTSUPP; | |
87 } | |
88 url_fskip(pb, header_size); | |
89 st = av_new_stream(s, 0); | |
90 if (!st) | |
91 return AVERROR_NOMEM; | |
92 st->codec->codec_type = CODEC_TYPE_AUDIO; | |
93 | |
94 voc->remaining_size = 0; | |
95 return 0; | |
96 } | |
97 | |
98 int | |
99 voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size) | |
100 { | |
101 voc_dec_context_t *voc = s->priv_data; | |
102 AVCodecContext *dec = st->codec; | |
103 ByteIOContext *pb = &s->pb; | |
104 voc_type_t type; | |
105 int size; | |
106 int sample_rate = 0; | |
107 int channels = 1; | |
108 | |
109 while (!voc->remaining_size) { | |
110 type = get_byte(pb); | |
111 if (type == VOC_TYPE_EOF) | |
112 return AVERROR_IO; | |
113 voc->remaining_size = get_le24(pb); | |
114 max_size -= 4; | |
115 | |
116 switch (type) { | |
117 case VOC_TYPE_VOICE_DATA: | |
118 dec->sample_rate = 1000000 / (256 - get_byte(pb)); | |
119 if (sample_rate) | |
120 dec->sample_rate = sample_rate; | |
121 dec->channels = channels; | |
122 dec->codec_id = codec_get_id(voc_codec_tags, get_byte(pb)); | |
1159
712f2acca29a
simplify the voc demuxer using av_get_bits_per_sample()
aurel
parents:
960
diff
changeset
|
123 dec->bits_per_sample = av_get_bits_per_sample(dec->codec_id); |
937 | 124 voc->remaining_size -= 2; |
125 max_size -= 2; | |
126 channels = 1; | |
127 break; | |
128 | |
129 case VOC_TYPE_VOICE_DATA_CONT: | |
130 break; | |
131 | |
132 case VOC_TYPE_EXTENDED: | |
133 sample_rate = get_le16(pb); | |
134 get_byte(pb); | |
135 channels = get_byte(pb) + 1; | |
136 sample_rate = 256000000 / (channels * (65536 - sample_rate)); | |
137 voc->remaining_size = 0; | |
138 max_size -= 4; | |
139 break; | |
140 | |
141 case VOC_TYPE_NEW_VOICE_DATA: | |
142 dec->sample_rate = get_le32(pb); | |
143 dec->bits_per_sample = get_byte(pb); | |
144 dec->channels = get_byte(pb); | |
145 dec->codec_id = codec_get_id(voc_codec_tags, get_le16(pb)); | |
146 url_fskip(pb, 4); | |
147 voc->remaining_size -= 12; | |
148 max_size -= 12; | |
149 break; | |
150 | |
151 default: | |
152 url_fskip(pb, voc->remaining_size); | |
153 max_size -= voc->remaining_size; | |
154 voc->remaining_size = 0; | |
155 break; | |
156 } | |
157 } | |
158 | |
159 dec->bit_rate = dec->sample_rate * dec->bits_per_sample; | |
160 | |
161 if (max_size <= 0) | |
162 max_size = voc_max_pkt_size; | |
163 size = FFMIN(voc->remaining_size, max_size); | |
164 voc->remaining_size -= size; | |
165 return av_get_packet(pb, pkt, size); | |
166 } | |
167 | |
168 static int voc_read_packet(AVFormatContext *s, AVPacket *pkt) | |
169 { | |
170 return voc_get_packet(s, pkt, s->streams[0], 0); | |
171 } | |
172 | |
173 static int voc_read_close(AVFormatContext *s) | |
174 { | |
175 return 0; | |
176 } | |
177 | |
1169 | 178 AVInputFormat voc_demuxer = { |
937 | 179 "voc", |
180 "Creative Voice File format", | |
181 sizeof(voc_dec_context_t), | |
182 voc_probe, | |
183 voc_read_header, | |
184 voc_read_packet, | |
185 voc_read_close, | |
186 }; | |
187 | |
188 #endif /* CONFIG_DEMUXERS */ | |
189 | |
190 | |
191 #ifdef CONFIG_MUXERS | |
192 | |
193 typedef struct voc_enc_context { | |
194 int param_written; | |
195 } voc_enc_context_t; | |
196 | |
197 static int voc_write_header(AVFormatContext *s) | |
198 { | |
199 ByteIOContext *pb = &s->pb; | |
200 const int header_size = 26; | |
201 const int version = 0x0114; | |
202 | |
203 if (s->nb_streams != 1 | |
204 || s->streams[0]->codec->codec_type != CODEC_TYPE_AUDIO) | |
205 return AVERROR_NOTSUPP; | |
206 | |
207 put_buffer(pb, voc_magic, sizeof(voc_magic) - 1); | |
208 put_le16(pb, header_size); | |
209 put_le16(pb, version); | |
210 put_le16(pb, ~version + 0x1234); | |
211 | |
212 return 0; | |
213 } | |
214 | |
215 static int voc_write_packet(AVFormatContext *s, AVPacket *pkt) | |
216 { | |
217 voc_enc_context_t *voc = s->priv_data; | |
218 AVCodecContext *enc = s->streams[0]->codec; | |
219 ByteIOContext *pb = &s->pb; | |
220 | |
221 if (!voc->param_written) { | |
222 int format = codec_get_tag(voc_codec_tags, enc->codec_id); | |
223 | |
224 if (format > 0xFF) { | |
225 put_byte(pb, VOC_TYPE_NEW_VOICE_DATA); | |
226 put_le24(pb, pkt->size + 12); | |
227 put_le32(pb, enc->sample_rate); | |
228 put_byte(pb, enc->bits_per_sample); | |
229 put_byte(pb, enc->channels); | |
230 put_le16(pb, format); | |
231 put_le32(pb, 0); | |
232 } else { | |
233 if (s->streams[0]->codec->channels > 1) { | |
234 put_byte(pb, VOC_TYPE_EXTENDED); | |
235 put_le24(pb, 4); | |
236 put_le16(pb, 65536-256000000/(enc->sample_rate*enc->channels)); | |
237 put_byte(pb, format); | |
238 put_byte(pb, enc->channels - 1); | |
239 } | |
240 put_byte(pb, VOC_TYPE_VOICE_DATA); | |
241 put_le24(pb, pkt->size + 2); | |
242 put_byte(pb, 256 - 1000000 / enc->sample_rate); | |
243 put_byte(pb, format); | |
244 } | |
245 voc->param_written = 1; | |
246 } else { | |
247 put_byte(pb, VOC_TYPE_VOICE_DATA_CONT); | |
248 put_le24(pb, pkt->size); | |
249 } | |
250 | |
251 put_buffer(pb, pkt->data, pkt->size); | |
252 return 0; | |
253 } | |
254 | |
255 static int voc_write_trailer(AVFormatContext *s) | |
256 { | |
257 put_byte(&s->pb, 0); | |
258 return 0; | |
259 } | |
260 | |
1169 | 261 AVOutputFormat voc_muxer = { |
937 | 262 "voc", |
263 "Creative Voice File format", | |
264 "audio/x-voc", | |
265 "voc", | |
266 sizeof(voc_enc_context_t), | |
267 CODEC_ID_PCM_U8, | |
268 CODEC_ID_NONE, | |
269 voc_write_header, | |
270 voc_write_packet, | |
271 voc_write_trailer, | |
272 }; | |
273 | |
274 #endif /* CONFIG_MUXERS */ |