Mercurial > mplayer.hg
comparison ima4.c @ 2399:35c767f8fea4
initial
author | alex |
---|---|
date | Tue, 23 Oct 2001 01:17:56 +0000 |
parents | |
children | 311676805f20 |
comparison
equal
deleted
inserted
replaced
2398:3679bb635267 | 2399:35c767f8fea4 |
---|---|
1 /* | |
2 IMA4:1 audio codec from QuickTime4Linux library. (http://www.heroinewarrior.com/) | |
3 */ | |
4 | |
5 #include "ima4.h" | |
6 | |
7 static int quicktime_ima4_step[89] = | |
8 { | |
9 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, | |
10 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, | |
11 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, | |
12 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, | |
13 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, | |
14 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, | |
15 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, | |
16 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, | |
17 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 | |
18 }; | |
19 | |
20 static int quicktime_ima4_index[16] = | |
21 { | |
22 -1, -1, -1, -1, 2, 4, 6, 8, | |
23 -1, -1, -1, -1, 2, 4, 6, 8 | |
24 }; | |
25 | |
26 /* Known by divine revelation */ | |
27 | |
28 #define BLOCK_SIZE 0x22 | |
29 #define SAMPLES_PER_BLOCK 0x40 | |
30 | |
31 /* ================================== private for ima4 */ | |
32 | |
33 | |
34 void ima4_decode_sample(int *predictor, int *nibble, int *index, int *step) | |
35 { | |
36 int difference, sign; | |
37 | |
38 /* Get new index value */ | |
39 *index += quicktime_ima4_index[*nibble]; | |
40 | |
41 if(*index < 0) *index = 0; | |
42 else | |
43 if(*index > 88) *index = 88; | |
44 | |
45 /* Get sign and magnitude from *nibble */ | |
46 sign = *nibble & 8; | |
47 *nibble = *nibble & 7; | |
48 | |
49 /* Get difference */ | |
50 difference = *step >> 3; | |
51 if(*nibble & 4) difference += *step; | |
52 if(*nibble & 2) difference += *step >> 1; | |
53 if(*nibble & 1) difference += *step >> 2; | |
54 | |
55 /* Predict value */ | |
56 if(sign) | |
57 *predictor -= difference; | |
58 else | |
59 *predictor += difference; | |
60 | |
61 if(*predictor > 32767) *predictor = 32767; | |
62 else | |
63 if(*predictor < -32768) *predictor = -32768; | |
64 | |
65 /* Update the step value */ | |
66 *step = quicktime_ima4_step[*index]; | |
67 } | |
68 | |
69 int ima4_decode_block(int16_t *output, unsigned char *input, int maxlen) | |
70 { | |
71 int predictor; | |
72 int index; | |
73 int step; | |
74 int i, nibble, nibble_count, block_size; | |
75 int olen = 0; | |
76 unsigned char *block_ptr; | |
77 unsigned char *input_end = input + BLOCK_SIZE; | |
78 // quicktime_ima4_codec_t *codec = ((quicktime_codec_t*)atrack->codec)->priv; | |
79 | |
80 /* Get the chunk header */ | |
81 predictor = *input++ << 8; | |
82 predictor |= *input++; | |
83 | |
84 index = predictor & 0x7f; | |
85 if(index > 88) index = 88; | |
86 | |
87 predictor &= 0xff80; | |
88 if(predictor & 0x8000) predictor -= 0x10000; | |
89 step = quicktime_ima4_step[index]; | |
90 | |
91 /* Read the input buffer sequentially, one nibble at a time */ | |
92 nibble_count = 0; | |
93 while(input < input_end) | |
94 { | |
95 nibble = nibble_count ? (*input++ >> 4) & 0x0f : *input & 0x0f; | |
96 | |
97 ima4_decode_sample(&predictor, &nibble, &index, &step); | |
98 if (olen+1 > maxlen) | |
99 break; | |
100 *output++ = predictor; | |
101 olen++; | |
102 | |
103 nibble_count ^= 1; | |
104 } | |
105 return(olen); | |
106 } | |
107 | |
108 #if 0 | |
109 void ima4_encode_sample(int *last_sample, int *last_index, int *nibble, int next_sample) | |
110 { | |
111 int difference, new_difference, mask, step; | |
112 | |
113 difference = next_sample - *last_sample; | |
114 *nibble = 0; | |
115 step = quicktime_ima4_step[*last_index]; | |
116 new_difference = step >> 3; | |
117 | |
118 if(difference < 0) | |
119 { | |
120 *nibble = 8; | |
121 difference = -difference; | |
122 } | |
123 | |
124 mask = 4; | |
125 while(mask) | |
126 { | |
127 if(difference >= step) | |
128 { | |
129 *nibble |= mask; | |
130 difference -= step; | |
131 new_difference += step; | |
132 } | |
133 | |
134 step >>= 1; | |
135 mask >>= 1; | |
136 } | |
137 | |
138 if(*nibble & 8) | |
139 *last_sample -= new_difference; | |
140 else | |
141 *last_sample += new_difference; | |
142 | |
143 if(*last_sample > 32767) *last_sample = 32767; | |
144 else | |
145 if(*last_sample < -32767) *last_sample = -32767; | |
146 | |
147 *last_index += quicktime_ima4_index[*nibble]; | |
148 | |
149 if(*last_index < 0) *last_index = 0; | |
150 else | |
151 if(*last_index > 88) *last_index= 88; | |
152 } | |
153 | |
154 #if 0 | |
155 void ima4_encode_block(quicktime_audio_map_t *atrack, unsigned char *output, int16_t *input, int step, int channel) | |
156 { | |
157 quicktime_ima4_codec_t *codec = ((quicktime_codec_t*)atrack->codec)->priv; | |
158 int i, nibble_count = 0, nibble, header; | |
159 | |
160 /* Get a fake starting sample */ | |
161 header = codec->last_samples[channel]; | |
162 /* Force rounding. */ | |
163 if(header < 0x7fc0) header += 0x40; | |
164 if(header < 0) header += 0x10000; | |
165 header &= 0xff80; | |
166 *output++ = (header & 0xff00) >> 8; | |
167 *output++ = (header & 0x80) + (codec->last_indexes[channel] & 0x7f); | |
168 | |
169 for(i = 0; i < SAMPLES_PER_BLOCK; i++) | |
170 { | |
171 ima4_encode_sample(&(codec->last_samples[channel]), | |
172 &(codec->last_indexes[channel]), | |
173 &nibble, | |
174 *input); | |
175 | |
176 if(nibble_count) | |
177 *output++ |= (nibble << 4); | |
178 else | |
179 *output = nibble; | |
180 | |
181 input += step; | |
182 nibble_count ^= 1; | |
183 } | |
184 } | |
185 #endif | |
186 /* Convert the number of samples in a chunk into the number of bytes in that */ | |
187 /* chunk. The number of samples in a chunk should end on a block boundary. */ | |
188 long ima4_samples_to_bytes(long samples, int channels) | |
189 { | |
190 long bytes = samples / SAMPLES_PER_BLOCK * BLOCK_SIZE * channels; | |
191 return bytes; | |
192 } | |
193 | |
194 /* Decode the chunk into the work buffer */ | |
195 int ima4_decode_chunk(quicktime_t *file, int track, long chunk, int channel) | |
196 { | |
197 int result = 0; | |
198 int i, j; | |
199 long chunk_samples, chunk_bytes; | |
200 unsigned char *chunk_ptr, *block_ptr; | |
201 quicktime_trak_t *trak = file->atracks[track].track; | |
202 quicktime_ima4_codec_t *codec = ((quicktime_codec_t*)file->atracks[track].codec)->priv; | |
203 | |
204 /* Get the byte count to read. */ | |
205 chunk_samples = quicktime_chunk_samples(trak, chunk); | |
206 chunk_bytes = ima4_samples_to_bytes(chunk_samples, file->atracks[track].channels); | |
207 | |
208 /* Get the buffer to read into. */ | |
209 if(codec->work_buffer && codec->work_size < chunk_samples) | |
210 { | |
211 free(codec->work_buffer); | |
212 codec->work_buffer = 0; | |
213 } | |
214 | |
215 if(!codec->work_buffer) | |
216 { | |
217 codec->work_size = chunk_samples; | |
218 codec->work_buffer = malloc(sizeof(int16_t) * codec->work_size); | |
219 } | |
220 | |
221 if(codec->read_buffer && codec->read_size < chunk_bytes) | |
222 { | |
223 free(codec->read_buffer); | |
224 codec->read_buffer = 0; | |
225 } | |
226 | |
227 if(!codec->read_buffer) | |
228 { | |
229 codec->read_size = chunk_bytes; | |
230 codec->read_buffer = malloc(codec->read_size); | |
231 } | |
232 | |
233 /* codec->work_size now holds the number of samples in the last chunk */ | |
234 /* codec->read_size now holds number of bytes in the last read buffer */ | |
235 | |
236 /* Read the entire chunk regardless of where the desired sample range starts. */ | |
237 result = quicktime_read_chunk(file, codec->read_buffer, track, chunk, 0, chunk_bytes); | |
238 | |
239 /* Now decode the chunk, one block at a time, until the total samples in the chunk */ | |
240 /* is reached. */ | |
241 | |
242 if(!result) | |
243 { | |
244 block_ptr = codec->read_buffer; | |
245 for(i = 0; i < chunk_samples; i += SAMPLES_PER_BLOCK) | |
246 { | |
247 for(j = 0; j < file->atracks[track].channels; j++) | |
248 { | |
249 if(j == channel) | |
250 ima4_decode_block(&(file->atracks[track]), &(codec->work_buffer[i]), block_ptr); | |
251 | |
252 block_ptr += BLOCK_SIZE; | |
253 } | |
254 } | |
255 } | |
256 codec->buffer_channel = channel; | |
257 codec->chunk = chunk; | |
258 | |
259 return result; | |
260 } | |
261 | |
262 | |
263 /* =================================== public for ima4 */ | |
264 | |
265 static int quicktime_delete_codec_ima4(quicktime_audio_map_t *atrack) | |
266 { | |
267 quicktime_ima4_codec_t *codec = ((quicktime_codec_t*)atrack->codec)->priv; | |
268 | |
269 if(codec->work_buffer) free(codec->work_buffer); | |
270 if(codec->read_buffer) free(codec->read_buffer); | |
271 if(codec->last_samples) free(codec->last_samples); | |
272 if(codec->last_indexes) free(codec->last_indexes); | |
273 codec->last_samples = 0; | |
274 codec->last_indexes = 0; | |
275 codec->read_buffer = 0; | |
276 codec->work_buffer = 0; | |
277 codec->chunk = 0; | |
278 codec->buffer_channel = 0; /* Channel of work buffer */ | |
279 codec->work_size = 0; /* Size of work buffer */ | |
280 codec->read_size = 0; | |
281 free(codec); | |
282 return 0; | |
283 } | |
284 | |
285 static int quicktime_decode_ima4(quicktime_t *file, | |
286 int16_t *output_i, | |
287 float *output_f, | |
288 long samples, | |
289 int track, | |
290 int channel) | |
291 { | |
292 int result = 0; | |
293 longest chunk, chunk_sample, chunk_bytes, chunk_samples; | |
294 longest i, chunk_start, chunk_end; | |
295 quicktime_trak_t *trak = file->atracks[track].track; | |
296 quicktime_ima4_codec_t *codec = ((quicktime_codec_t*)file->atracks[track].codec)->priv; | |
297 | |
298 /* Get the first chunk with this routine and then increase the chunk number. */ | |
299 quicktime_chunk_of_sample(&chunk_sample, &chunk, trak, file->atracks[track].current_position); | |
300 | |
301 /* Read chunks and extract ranges of samples until the output is full. */ | |
302 for(i = 0; i < samples && !result; ) | |
303 { | |
304 /* Get chunk we're on. */ | |
305 chunk_samples = quicktime_chunk_samples(trak, chunk); | |
306 | |
307 if(!codec->work_buffer || | |
308 codec->chunk != chunk || | |
309 codec->buffer_channel != channel) | |
310 { | |
311 /* read a new chunk if necessary */ | |
312 result = ima4_decode_chunk(file, track, chunk, channel); | |
313 } | |
314 | |
315 /* Get boundaries from the chunk */ | |
316 chunk_start = 0; | |
317 if(chunk_sample < file->atracks[track].current_position) | |
318 chunk_start = file->atracks[track].current_position - chunk_sample; | |
319 | |
320 chunk_end = chunk_samples; | |
321 if(chunk_sample + chunk_end > file->atracks[track].current_position + samples) | |
322 chunk_end = file->atracks[track].current_position + samples - chunk_sample; | |
323 | |
324 /* Read from the chunk */ | |
325 if(output_i) | |
326 { | |
327 /*printf("decode_ima4 1 chunk %ld %ld-%ld output %ld\n", chunk, chunk_start + chunk_sample, chunk_end + chunk_sample, i); */ | |
328 while(chunk_start < chunk_end) | |
329 { | |
330 output_i[i++] = codec->work_buffer[chunk_start++]; | |
331 } | |
332 /*printf("decode_ima4 2\n"); */ | |
333 } | |
334 else | |
335 if(output_f) | |
336 { | |
337 while(chunk_start < chunk_end) | |
338 { | |
339 output_f[i++] = (float)codec->work_buffer[chunk_start++] / 32767; | |
340 } | |
341 } | |
342 | |
343 chunk++; | |
344 chunk_sample += chunk_samples; | |
345 } | |
346 | |
347 return result; | |
348 } | |
349 | |
350 static int quicktime_encode_ima4(quicktime_t *file, | |
351 int16_t **input_i, | |
352 float **input_f, | |
353 int track, | |
354 long samples) | |
355 { | |
356 int result = 0; | |
357 longest i, j, step; | |
358 longest chunk_bytes; | |
359 longest overflow_start; | |
360 longest offset; | |
361 longest chunk_samples; /* Samples in the current chunk to be written */ | |
362 quicktime_audio_map_t *track_map = &(file->atracks[track]); | |
363 quicktime_ima4_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv; | |
364 int16_t *input_ptr; | |
365 unsigned char *output_ptr; | |
366 | |
367 /* Get buffer sizes */ | |
368 if(codec->work_buffer && codec->work_size < (samples + codec->work_overflow + 1) * track_map->channels) | |
369 { | |
370 /* Create new buffer */ | |
371 longest new_size = (samples + codec->work_overflow + 1) * track_map->channels; | |
372 int16_t *new_buffer = malloc(sizeof(int16_t) * new_size); | |
373 | |
374 /* Copy overflow */ | |
375 for(i = 0; i < codec->work_overflow * track_map->channels; i++) | |
376 new_buffer[i] = codec->work_buffer[i]; | |
377 | |
378 /* Swap pointers. */ | |
379 free(codec->work_buffer); | |
380 codec->work_buffer = new_buffer; | |
381 codec->work_size = new_size; | |
382 } | |
383 else | |
384 if(!codec->work_buffer) | |
385 { | |
386 /* No buffer in the first place. */ | |
387 codec->work_size = (samples + codec->work_overflow) * track_map->channels; | |
388 /* Make the allocation enough for at least the flush routine. */ | |
389 if(codec->work_size < SAMPLES_PER_BLOCK * track_map->channels) | |
390 codec->work_size = SAMPLES_PER_BLOCK * track_map->channels; | |
391 codec->work_buffer = malloc(sizeof(int16_t) * codec->work_size); | |
392 } | |
393 | |
394 /* Get output size */ | |
395 chunk_bytes = ima4_samples_to_bytes(samples + codec->work_overflow, track_map->channels); | |
396 if(codec->read_buffer && codec->read_size < chunk_bytes) | |
397 { | |
398 free(codec->read_buffer); | |
399 codec->read_buffer = 0; | |
400 } | |
401 | |
402 if(!codec->read_buffer) | |
403 { | |
404 codec->read_buffer = malloc(chunk_bytes); | |
405 codec->read_size = chunk_bytes; | |
406 } | |
407 | |
408 if(!codec->last_samples) | |
409 { | |
410 codec->last_samples = malloc(sizeof(int) * track_map->channels); | |
411 for(i = 0; i < track_map->channels; i++) | |
412 { | |
413 codec->last_samples[i] = 0; | |
414 } | |
415 } | |
416 | |
417 if(!codec->last_indexes) | |
418 { | |
419 codec->last_indexes = malloc(sizeof(int) * track_map->channels); | |
420 for(i = 0; i < track_map->channels; i++) | |
421 { | |
422 codec->last_indexes[i] = 0; | |
423 } | |
424 } | |
425 | |
426 /* Arm the input buffer after the last overflow */ | |
427 step = track_map->channels; | |
428 for(j = 0; j < track_map->channels; j++) | |
429 { | |
430 input_ptr = codec->work_buffer + codec->work_overflow * track_map->channels + j; | |
431 | |
432 if(input_i) | |
433 { | |
434 for(i = 0; i < samples; i++) | |
435 { | |
436 *input_ptr = input_i[j][i]; | |
437 input_ptr += step; | |
438 } | |
439 } | |
440 else | |
441 if(input_f) | |
442 { | |
443 for(i = 0; i < samples; i++) | |
444 { | |
445 *input_ptr = (int16_t)(input_f[j][i] * 32767); | |
446 input_ptr += step; | |
447 } | |
448 } | |
449 } | |
450 | |
451 /* Encode from the input buffer to the read_buffer up to a multiple of */ | |
452 /* blocks. */ | |
453 input_ptr = codec->work_buffer; | |
454 output_ptr = codec->read_buffer; | |
455 | |
456 for(i = 0; | |
457 i + SAMPLES_PER_BLOCK <= samples + codec->work_overflow; | |
458 i += SAMPLES_PER_BLOCK) | |
459 { | |
460 for(j = 0; j < track_map->channels; j++) | |
461 { | |
462 ima4_encode_block(track_map, output_ptr, input_ptr + j, track_map->channels, j); | |
463 | |
464 output_ptr += BLOCK_SIZE; | |
465 } | |
466 input_ptr += SAMPLES_PER_BLOCK * track_map->channels; | |
467 } | |
468 | |
469 /* Write to disk */ | |
470 chunk_samples = (longest)((samples + codec->work_overflow) / SAMPLES_PER_BLOCK) * SAMPLES_PER_BLOCK; | |
471 | |
472 /*printf("quicktime_encode_ima4 1 %ld\n", chunk_samples); */ | |
473 /* The block division may result in 0 samples getting encoded. */ | |
474 /* Don't write 0 samples. */ | |
475 if(chunk_samples) | |
476 { | |
477 offset = quicktime_position(file); | |
478 result = quicktime_write_data(file, codec->read_buffer, chunk_bytes); | |
479 if(result) result = 0; else result = 1; /* defeat fwrite's return */ | |
480 quicktime_update_tables(file, | |
481 track_map->track, | |
482 offset, | |
483 track_map->current_chunk, | |
484 track_map->current_position, | |
485 chunk_samples, | |
486 0); | |
487 file->atracks[track].current_chunk++; | |
488 } | |
489 | |
490 /* Move the last overflow to the front */ | |
491 overflow_start = i; | |
492 input_ptr = codec->work_buffer; | |
493 for(i = overflow_start * track_map->channels ; | |
494 i < (samples + codec->work_overflow) * track_map->channels; | |
495 i++) | |
496 { | |
497 *input_ptr++ = codec->work_buffer[i]; | |
498 } | |
499 codec->work_overflow = samples + codec->work_overflow - overflow_start; | |
500 | |
501 return result; | |
502 } | |
503 | |
504 int quicktime_flush_ima4(quicktime_t *file, int track) | |
505 { | |
506 quicktime_audio_map_t *track_map = &(file->atracks[track]); | |
507 quicktime_ima4_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv; | |
508 int result = 0; | |
509 int i; | |
510 | |
511 /*printf("quicktime_flush_ima4 %ld\n", codec->work_overflow); */ | |
512 if(codec->work_overflow) | |
513 { | |
514 /* Zero out enough to get a block */ | |
515 i = codec->work_overflow * track_map->channels; | |
516 while(i < SAMPLES_PER_BLOCK * track_map->channels) | |
517 { | |
518 codec->work_buffer[i++] = 0; | |
519 } | |
520 codec->work_overflow = i / track_map->channels + 1; | |
521 /* Write the work_overflow only. */ | |
522 result = quicktime_encode_ima4(file, 0, 0, track, 0); | |
523 } | |
524 return result; | |
525 } | |
526 | |
527 void quicktime_init_codec_ima4(quicktime_audio_map_t *atrack) | |
528 { | |
529 quicktime_ima4_codec_t *codec; | |
530 | |
531 /* Init public items */ | |
532 ((quicktime_codec_t*)atrack->codec)->priv = calloc(1, sizeof(quicktime_ima4_codec_t)); | |
533 ((quicktime_codec_t*)atrack->codec)->delete_acodec = quicktime_delete_codec_ima4; | |
534 ((quicktime_codec_t*)atrack->codec)->decode_video = 0; | |
535 ((quicktime_codec_t*)atrack->codec)->encode_video = 0; | |
536 ((quicktime_codec_t*)atrack->codec)->decode_audio = quicktime_decode_ima4; | |
537 ((quicktime_codec_t*)atrack->codec)->encode_audio = quicktime_encode_ima4; | |
538 | |
539 /* Init private items */ | |
540 codec = ((quicktime_codec_t*)atrack->codec)->priv; | |
541 codec->work_buffer = 0; | |
542 codec->read_buffer = 0; | |
543 codec->chunk = 0; | |
544 codec->buffer_channel = 0; | |
545 codec->work_overflow = 0; | |
546 codec->work_size = 0; | |
547 codec->read_size = 0; | |
548 codec->last_samples = 0; | |
549 codec->last_indexes = 0; | |
550 } | |
551 #endif |