📄 ima4.c
字号:
/******************************************************************************* ima4.c libquicktime - A library for reading and writing quicktime/avi/mp4 files. http://libquicktime.sourceforge.net Copyright (C) 2002 Heroine Virtual Ltd. Copyright (C) 2002-2007 Members of the libquicktime project. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*******************************************************************************/ #include "lqt_private.h"#define LQT_LIBQUICKTIME#include <quicktime/lqt_codecapi.h>#include <stdlib.h>#include <string.h>#include "audiocodec.h"#define LOG_DOMAIN "ima4"/* Known by divine revelation */#define BLOCK_SIZE 0x22#define SAMPLES_PER_BLOCK 0x40typedef struct{/* Starting information for all channels during encoding. */ int *last_samples, *last_indexes;/* Buffer for samples */ int16_t * sample_buffer; /* SAMPLES_PER_BLOCK * channels (interleaved) */ int sample_buffer_size; /* samples from last en/decode call */ /* Buffer for chunks */ int chunk_buffer_size; int chunk_buffer_alloc; int chunk_samples; uint8_t * chunk_buffer; uint8_t * chunk_buffer_ptr; int decode_initialized; } quicktime_ima4_codec_t;static int ima4_step[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767};static int ima4_index[16] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8};/* ================================== private for ima4 */static void ima4_decode_sample(int *predictor, int *nibble, int *index, int *step){ int difference, sign;/* Get new index value */ *index += ima4_index[*nibble]; if(*index < 0) *index = 0; else if(*index > 88) *index = 88;/* Get sign and magnitude from *nibble */ sign = *nibble & 8; *nibble = *nibble & 7;/* Get difference */ difference = *step >> 3; if(*nibble & 4) difference += *step; if(*nibble & 2) difference += *step >> 1; if(*nibble & 1) difference += *step >> 2;/* Predict value */ if(sign) *predictor -= difference; else *predictor += difference; if(*predictor > 32767) *predictor = 32767; else if(*predictor < -32768) *predictor = -32768;/* Update the step value */ *step = ima4_step[*index];}static void ima4_decode_block(quicktime_audio_map_t *atrack, int16_t *output, unsigned char *input, int channels){ int predictor; int index; int step; int nibble, nibble_count; unsigned char *input_end = input + BLOCK_SIZE;/* Get the chunk header */ predictor = *input++ << 8; predictor |= *input++; index = predictor & 0x7f; if(index > 88) index = 88; predictor &= 0xff80; if(predictor & 0x8000) predictor -= 0x10000; step = ima4_step[index];/* Read the input buffer sequentially, one nibble at a time */ nibble_count = 0; while(input < input_end) { nibble = nibble_count ? (*input++ >> 4) & 0x0f : *input & 0x0f; ima4_decode_sample(&predictor, &nibble, &index, &step); *output = predictor; output += channels; nibble_count ^= 1; }}static void ima4_encode_sample(int *last_sample, int *last_index, int *nibble, int next_sample){ int difference, new_difference, mask, step; difference = next_sample - *last_sample; *nibble = 0; step = ima4_step[*last_index]; new_difference = step >> 3; if(difference < 0) { *nibble = 8; difference = -difference; } mask = 4; while(mask) { if(difference >= step) { *nibble |= mask; difference -= step; new_difference += step; } step >>= 1; mask >>= 1; } if(*nibble & 8) *last_sample -= new_difference; else *last_sample += new_difference; if(*last_sample > 32767) *last_sample = 32767; else if(*last_sample < -32767) *last_sample = -32767; *last_index += ima4_index[*nibble]; if(*last_index < 0) *last_index = 0; else if(*last_index > 88) *last_index= 88;}static void ima4_encode_block(quicktime_audio_map_t *atrack, unsigned char *output, int16_t *input, int step, int channel){ quicktime_ima4_codec_t *codec = ((quicktime_codec_t*)atrack->codec)->priv; int i, nibble_count = 0, nibble, header;/* Get a fake starting sample */ header = codec->last_samples[channel];/* Force rounding. */ if(header < 0x7fc0) header += 0x40; if(header < 0) header += 0x10000; header &= 0xff80; *output++ = (header & 0xff00) >> 8; *output++ = (header & 0x80) + (codec->last_indexes[channel] & 0x7f); for(i = 0; i < SAMPLES_PER_BLOCK; i++) { ima4_encode_sample(&(codec->last_samples[channel]), &(codec->last_indexes[channel]), &nibble, *input); if(nibble_count) *output++ |= (nibble << 4); else *output = nibble; input += step; nibble_count ^= 1; }}/* Convert the number of samples in a chunk into the number of bytes in that *//* chunk. The number of samples in a chunk should end on a block boundary. */static long ima4_samples_to_bytes(long samples, int channels) { return (samples / SAMPLES_PER_BLOCK) * BLOCK_SIZE * channels; }#if 0static int read_audio_chunk(quicktime_t * file, int track, long chunk, uint8_t ** buffer, int * buffer_alloc) { int bytes, samples, bytes_from_samples; bytes = lqt_read_audio_chunk(file, track, chunk, buffer, buffer_alloc, &samples); // bytes_from_samples = ima4_samples_to_bytes(samples, file->atracks[track].channels); // if(bytes > bytes_from_samples) // return bytes_from_samples; // else return bytes; }#endif/* =================================== public for ima4 */static int delete_codec(quicktime_audio_map_t *atrack){ quicktime_ima4_codec_t *codec = ((quicktime_codec_t*)atrack->codec)->priv; if(codec->last_samples) free(codec->last_samples); if(codec->last_indexes) free(codec->last_indexes); if(codec->chunk_buffer) free(codec->chunk_buffer); if(codec->sample_buffer) free(codec->sample_buffer); free(codec); return 0;}static int decode(quicktime_t *file, void * _output, long samples, int track){ int64_t chunk_sample; int64_t i; int64_t chunk; int16_t * output = (int16_t*)_output; int samples_decoded, samples_copied; quicktime_ima4_codec_t *codec = ((quicktime_codec_t*)file->atracks[track].codec)->priv; int samples_to_skip = 0; if(!_output) /* Global initialization */ { return 0; } if(!codec->decode_initialized) { codec->decode_initialized = 1; codec->sample_buffer = malloc(sizeof(*(codec->sample_buffer)) * file->atracks[track].channels * SAMPLES_PER_BLOCK); /* Read first chunk */ codec->chunk_buffer_size = lqt_read_audio_chunk(file, track, file->atracks[track].current_chunk, &(codec->chunk_buffer), &(codec->chunk_buffer_alloc), &(codec->chunk_samples)); if(codec->chunk_buffer_size <= 0) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -