ima.c
来自「The Audio File Library provides a unifor」· C语言 代码 · 共 270 行
C
270 行
/* Audio File Library Copyright (C) 2001, Silicon Graphics, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA.*//* ima.c This module implements IMA ADPCM compression for the Audio File Library.*/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <errno.h>#include <string.h>#include <assert.h>#include <audiofile.h>#include "afinternal.h"#include "modules.h"#include "units.h"#include "compression.h"#include "byteorder.h"#include "util.h"#include "adpcm.h"#define CHNK(X)static _AFmodule ima_adpcm_decompress;typedef struct{ _Track *track; AFvirtualfile *fh; int blockAlign, samplesPerBlock; AFframecount framesToIgnore;} ima_adpcm_data;static int ima_adpcm_decode_block (ima_adpcm_data *ima, u_int8_t *encoded, int16_t *decoded){ int outputLength; struct adpcm_state state; outputLength = ima->samplesPerBlock * sizeof (int16_t) * ima->track->f.channelCount; state.valprev = (encoded[1]<<8) | encoded[0]; if (encoded[1] & 0x80) state.valprev -= 0x10000; state.index = encoded[2]; *decoded++ = state.valprev; encoded += 4; _af_adpcm_decoder(encoded, decoded, ima->samplesPerBlock - 1, &state); return outputLength;}bool _af_ima_adpcm_format_ok (_AudioFormat *f){ if (f->channelCount != 1) { _af_error(AF_BAD_COMPRESSION, "IMA ADPCM compression requires 1 channel"); return AF_FALSE; } if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || f->sampleWidth != 16) { _af_error(AF_BAD_COMPRESSION, "IMA ADPCM compression requires 16-bit signed integer format"); f->sampleFormat = AF_SAMPFMT_TWOSCOMP; f->sampleWidth = 16; /* non-fatal */ } if (f->byteOrder != AF_BYTEORDER_BIGENDIAN) { _af_error(AF_BAD_COMPRESSION, "IMA ADPCM compression requires big endian format"); f->byteOrder = AF_BYTEORDER_BIGENDIAN; /* non-fatal */ } return AF_TRUE;}static void ima_adpcm_decompress_describe (_AFmoduleinst *i){/* XXXmpruett this is probably the correct way to go, but other things need to be changed first. i->outc->f.byteOrder = _AF_BYTEORDER_NATIVE;*/ i->outc->f.compressionType = AF_COMPRESSION_NONE; i->outc->f.compressionParams = AU_NULL_PVLIST;}_AFmoduleinst _af_ima_adpcm_init_decompress (_Track *track, AFvirtualfile *fh, bool seekok, bool headerless, AFframecount *chunkframes){ _AFmoduleinst ret = _AFnewmodinst(&ima_adpcm_decompress); ima_adpcm_data *d; AUpvlist pv; int i; long l; void *v; assert(af_ftell(fh) == track->fpos_first_frame); d = (ima_adpcm_data *) _af_malloc(sizeof (ima_adpcm_data)); d->track = track; d->fh = fh; d->track->frames2ignore = 0; d->track->fpos_next_frame = d->track->fpos_first_frame; pv = d->track->f.compressionParams; if (_af_pv_getlong(pv, _AF_SAMPLES_PER_BLOCK, &l)) d->samplesPerBlock = l; else _af_error(AF_BAD_CODEC_CONFIG, "samples per block not set"); if (_af_pv_getlong(pv, _AF_BLOCK_SIZE, &l)) d->blockAlign = l; else _af_error(AF_BAD_CODEC_CONFIG, "block size not set"); *chunkframes = d->samplesPerBlock / d->track->f.channelCount; ret.modspec = d; return ret;}static void ima_adpcm_run_pull (_AFmoduleinst *module){ ima_adpcm_data *d = (ima_adpcm_data *) module->modspec; AFframecount frames2read = module->outc->nframes; AFframecount nframes = 0; int i, framesPerBlock, blockCount; ssize_t blocksRead, bytesDecoded; framesPerBlock = d->samplesPerBlock / d->track->f.channelCount; assert(module->outc->nframes % framesPerBlock == 0); blockCount = module->outc->nframes / framesPerBlock; /* Read the compressed frames. */ blocksRead = af_fread(module->inc->buf, d->blockAlign, blockCount, d->fh); /* This condition would indicate that the file is bad. */ if (blocksRead < 0) { if (d->track->filemodhappy) { _af_error(AF_BAD_READ, "file missing data"); d->track->filemodhappy = AF_FALSE; } } if (blocksRead < blockCount) blockCount = blocksRead; /* Decompress into module->outc. */ for (i=0; i<blockCount; i++) { bytesDecoded = ima_adpcm_decode_block(d, (u_int8_t *) module->inc->buf + i * d->blockAlign, (int16_t *) module->outc->buf + i * d->samplesPerBlock); nframes += framesPerBlock; } d->track->nextfframe += nframes; if (blocksRead > 0) d->track->fpos_next_frame += blocksRead * d->blockAlign; assert(af_ftell(d->fh) == d->track->fpos_next_frame); /* If we got EOF from read, then we return the actual amount read. Complain only if there should have been more frames in the file. */ if (d->track->totalfframes != -1 && nframes != frames2read) { /* Report error if we haven't already */ if (d->track->filemodhappy) { _af_error(AF_BAD_READ, "file missing data -- read %d frames, should be %d", d->track->nextfframe, d->track->totalfframes); d->track->filemodhappy = AF_FALSE; } } module->outc->nframes = nframes;}static void ima_adpcm_reset1 (_AFmoduleinst *i){ ima_adpcm_data *d = (ima_adpcm_data *) i->modspec; AFframecount nextTrackFrame; int framesPerBlock; framesPerBlock = d->samplesPerBlock / d->track->f.channelCount; nextTrackFrame = d->track->nextfframe; d->track->nextfframe = (nextTrackFrame / framesPerBlock) * framesPerBlock; d->framesToIgnore = nextTrackFrame - d->track->nextfframe; /* postroll = frames2ignore */}static void ima_adpcm_reset2 (_AFmoduleinst *i){ ima_adpcm_data *d = (ima_adpcm_data *) i->modspec; int framesPerBlock; framesPerBlock = d->samplesPerBlock / d->track->f.channelCount; d->track->fpos_next_frame = d->track->fpos_first_frame + d->blockAlign * (d->track->nextfframe / framesPerBlock); d->track->frames2ignore += d->framesToIgnore; assert(d->track->nextfframe % framesPerBlock == 0);}static _AFmodule ima_adpcm_decompress ={ "ima_adpcm_decompress", ima_adpcm_decompress_describe, AF_NULL, AF_NULL, ima_adpcm_run_pull, ima_adpcm_reset1, ima_adpcm_reset2, AF_NULL, AF_NULL, AF_NULL, AF_NULL, _AFfreemodspec};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?