/* * libmad - MPEG audio decoder library * Copyright (C) 2000-2004 Underbit Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: decoder.c,v 1.22 2004/01/23 09:41:32 rob Exp $ */ #include # include #include # ifdef HAVE_CONFIG_H # include "config.h" # endif # include "global.h" # ifdef HAVE_SYS_TYPES_H # include # endif # ifdef HAVE_SYS_WAIT_H # include # endif # ifdef HAVE_UNISTD_H # include # endif # ifdef HAVE_FCNTL_H # include # endif # include # ifdef HAVE_ERRNO_H # include # endif # include "stream.h" # include "frame.h" # include "synth.h" # include "decoder.h" #ifndef _WIN32 #include "adec-armdec-mgt.h" #include #define LOG_TAG "MadDecoder" #ifdef ANDROID_BUILD #define audio_codec_print(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #else #define audio_codec_print(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #endif #else #define audio_codec_print printf #endif #ifndef __unused #define __unused __attribute__((unused)) #endif #define MUTE_S 0.08 //char *pcm_out_data; //int *pcm_out_len; //enum mad_flow(*error_func)(void *, struct mad_stream *, struct mad_frame *); //void *error_data; //int bad_last_frame = 0; //struct mad_stream *stream; //struct mad_frame *frame; //struct mad_synth *synth; //int result = 0; /* * This is a private message structure. A generic pointer to this structure * is passed to each of the callback functions. Put here any data you need * to access from within the callbacks. */ struct buffer { unsigned char *start; unsigned long length; }; enum tagtype { TAGTYPE_NONE = 0, TAGTYPE_ID3V1, TAGTYPE_ID3V2, TAGTYPE_ID3V2_FOOTER }; unsigned long id3_parse_uint(char **ptr, unsigned int bytes) { unsigned long value = 0; switch (bytes) { case 4: value = (value << 8) | *(*ptr)++; case 3: value = (value << 8) | *(*ptr)++; case 2: value = (value << 8) | *(*ptr)++; case 1: value = (value << 8) | *(*ptr)++; } return value; } unsigned long id3_parse_syncsafe(char **ptr, unsigned int bytes) { unsigned long value = 0; switch (bytes) { case 5: value = (value << 4) | (*(*ptr)++ & 0x0f); case 4: value = (value << 7) | (*(*ptr)++ & 0x7f); value = (value << 7) | (*(*ptr)++ & 0x7f); value = (value << 7) | (*(*ptr)++ & 0x7f); value = (value << 7) | (*(*ptr)++ & 0x7f); } return value; } static void parse_header(char **ptr, unsigned int *version, int *flags, int *size) { *ptr += 3; *version = id3_parse_uint(ptr, 2); *flags = id3_parse_uint(ptr, 1); *size = id3_parse_syncsafe(ptr, 4); } enum tagtype tagtype(char *data, int length) { if (length >= 3 && data[0] == 'T' && data[1] == 'A' && data[2] == 'G') { return TAGTYPE_ID3V1; } if (length >= 10 && ((data[0] == 'I' && data[1] == 'D' && data[2] == '3') || (data[0] == '3' && data[1] == 'D' && data[2] == 'I')) && data[3] < 0xff && data[4] < 0xff && data[6] < 0x80 && data[7] < 0x80 && data[8] < 0x80 && data[9] < 0x80) { return data[0] == 'I' ? TAGTYPE_ID3V2 : TAGTYPE_ID3V2_FOOTER; } return TAGTYPE_NONE; } int id3_tag_query(char *data, int length) { unsigned int version; int flags; int size; switch (tagtype(data, length)) { case TAGTYPE_ID3V1: return 128; case TAGTYPE_ID3V2: parse_header(&data, &version, &flags, &size); if (flags) { size += 10; } return 10 + size; case TAGTYPE_ID3V2_FOOTER: parse_header(&data, &version, &flags, &size); return -size - 10; case TAGTYPE_NONE: break; } return 0; } /* * NAME: decoder->init() * DESCRIPTION: initialize a decoder object with callback routines */ void mad_decoder_init(struct mad_decoder *decoder, void *data __unused, enum mad_flow(*input_func)(void *, struct mad_stream *), enum mad_flow(*header_func)(void *, struct mad_header const *), enum mad_flow(*filter_func)(void *, struct mad_stream const *, struct mad_frame *), enum mad_flow(*output_func)(struct mad_decoder *, struct mad_header const *, struct mad_pcm *), enum mad_flow(*error_func)(void *, struct mad_stream *, struct mad_frame *), enum mad_flow(*message_func)(void *, void *, unsigned int *)) { decoder->mode = -1; decoder->last_ch_num = -1; decoder->last_sr = -1; decoder->bad_last_frame = 0; decoder->options = 0; decoder->decoded_nb_frames = 0; decoder->droppped_nb_frames = 0; decoder->error_nb_frames = 0; decoder->bit_rate = 0; decoder->async.pid = 0; decoder->async.in = -1; decoder->async.out = -1; decoder->sync = 0; decoder->cb_data = 0;//data; decoder->input_func = input_func; decoder->header_func = header_func; decoder->filter_func = filter_func; decoder->output_func = output_func; decoder->error_func = error_func; decoder->message_func = message_func; } int mad_decoder_finish(struct mad_decoder *decoder __unused) { # if defined(USE_ASYNC) if (decoder->mode == MAD_DECODER_MODE_ASYNC && decoder->async.pid) { pid_t pid; int status; close(decoder->async.in); do { pid = waitpid(decoder->async.pid, &status, 0); } while (pid == -1 && errno == EINTR); decoder->mode = -1; close(decoder->async.out); decoder->async.pid = 0; decoder->async.in = -1; decoder->async.out = -1; if (pid == -1) { return -1; } return (!WIFEXITED(status) || WEXITSTATUS(status)) ? -1 : 0; } # endif return 0; } # if defined(USE_ASYNC) static enum mad_flow send_io(int fd, void const *data, size_t len) { char const *ptr = data; ssize_t count; while (len) { do { count = write(fd, ptr, len); } while (count == -1 && errno == EINTR); if (count == -1) { return MAD_FLOW_BREAK; } len -= count; ptr += count; } return MAD_FLOW_CONTINUE; } static enum mad_flow receive_io(int fd, void *buffer, size_t len) { char *ptr = buffer; ssize_t count; while (len) { do { count = read(fd, ptr, len); } while (count == -1 && errno == EINTR); if (count == -1) { return (errno == EAGAIN) ? MAD_FLOW_IGNORE : MAD_FLOW_BREAK; } else if (count == 0) { return MAD_FLOW_STOP; } len -= count; ptr += count; } return MAD_FLOW_CONTINUE; } static enum mad_flow receive_io_blocking(int fd, void *buffer, size_t len) { int flags, blocking; enum mad_flow result; flags = fcntl(fd, F_GETFL); if (flags == -1) { return MAD_FLOW_BREAK; } blocking = flags & ~O_NONBLOCK; if (blocking != flags && fcntl(fd, F_SETFL, blocking) == -1) { return MAD_FLOW_BREAK; } result = receive_io(fd, buffer, len); if (flags != blocking && fcntl(fd, F_SETFL, flags) == -1) { return MAD_FLOW_BREAK; } return result; } static enum mad_flow send(int fd, void const *message, unsigned int size) { enum mad_flow result; /* send size */ result = send_io(fd, &size, sizeof(size)); /* send message */ if (result == MAD_FLOW_CONTINUE) { result = send_io(fd, message, size); } return result; } static enum mad_flow receive(int fd, void **message, unsigned int *size) { enum mad_flow result; unsigned int actual; if (*message == 0) { *size = 0; } /* receive size */ result = receive_io(fd, &actual, sizeof(actual)); /* receive message */ if (result == MAD_FLOW_CONTINUE) { if (actual > *size) { actual -= *size; } else { *size = actual; actual = 0; } if (*size > 0) { if (*message == 0) { *message = malloc(*size); if (*message == 0) { return MAD_FLOW_BREAK; } } result = receive_io_blocking(fd, *message, *size); } /* throw away remainder of message */ while (actual && result == MAD_FLOW_CONTINUE) { char sink[256]; unsigned int len; len = actual > sizeof(sink) ? sizeof(sink) : actual; result = receive_io_blocking(fd, sink, len); actual -= len; } } return result; } static enum mad_flow check_message(struct mad_decoder *decoder) { enum mad_flow result; void *message = 0; unsigned int size; result = receive(decoder->async.in, &message, &size); if (result == MAD_FLOW_CONTINUE) { if (decoder->message_func == 0) { size = 0; } else { result = decoder->message_func(decoder->cb_data, message, &size); if (result == MAD_FLOW_IGNORE || result == MAD_FLOW_BREAK) { size = 0; } } if (send(decoder->async.out, message, size) != MAD_FLOW_CONTINUE) { result = MAD_FLOW_BREAK; } } if (message) { free(message); } return result; } # endif static enum mad_flow error_default(void *data, struct mad_stream *stream, struct mad_frame *frame) { int *bad_last_frame = data; switch (stream->error) { case MAD_ERROR_BADCRC: if (*bad_last_frame) { mad_frame_mute(frame); } else { *bad_last_frame = 1; } return MAD_FLOW_IGNORE; default: return MAD_FLOW_CONTINUE; } } static int run_sync(struct mad_decoder *decoder) { /* if (decoder->input_func == 0) return 0; if (decoder->error_func) { error_func = decoder->error_func; //error_data = decoder->cb_data; } else { error_func = error_default; error_data = &bad_last_frame; } stream = &decoder->sync->stream; frame = &decoder->sync->frame; synth = &decoder->sync->synth; mad_stream_init(stream); mad_frame_init(frame); mad_synth_init(synth); mad_stream_options(stream, decoder->options); */ do { switch (decoder->input_func(decoder->cb_data, &(decoder->sync->stream))) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: continue; case MAD_FLOW_CONTINUE: break; } while (1) { # if defined(USE_ASYNC) if (decoder->mode == MAD_DECODER_MODE_ASYNC) { switch (check_message(decoder)) { case MAD_FLOW_IGNORE: case MAD_FLOW_CONTINUE: break; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_STOP: goto done; } } # endif if (decoder->header_func) { if (mad_header_decode(&(decoder->sync->frame.header), &(decoder->sync->stream)) == -1) { if (!MAD_RECOVERABLE(decoder->sync->stream.error)) { break; } switch (decoder->error_func(decoder->cb_data, &(decoder->sync->stream), &(decoder->sync->frame))) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: case MAD_FLOW_CONTINUE: default: continue; } } switch (decoder->header_func(decoder->cb_data,&(decoder->sync->frame.header))) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: continue; case MAD_FLOW_CONTINUE: break; } } if (mad_frame_decode(&(decoder->sync->frame),&(decoder->sync->stream)) == -1) { if (!MAD_RECOVERABLE(decoder->sync->stream.error)) { break; } switch (decoder->error_func(decoder->cb_data, &decoder->sync->stream, &decoder->sync->frame)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: decoder->droppped_nb_frames++; decoder->error_nb_frames++; goto fail; case MAD_FLOW_IGNORE: // for this error,we should skip one bytes for another frame sync,otherwise no chance to cosume data again if (decoder->sync->stream.this_frame == decoder->sync->stream.buffer) { decoder->sync->stream.this_frame = decoder->sync->stream.buffer + 1; } audio_codec_print("[%s,%d] MAD_FLOW_IGNORE\n", __FUNCTION__, __LINE__); goto fail; break; case MAD_FLOW_CONTINUE: default: if (decoder->sync->stream.error >= MAD_ERROR_LOSTSYNC) { decoder->droppped_nb_frames++; decoder->error_nb_frames++; } continue; } } else { decoder->decoded_nb_frames++; decoder->bad_last_frame = 0; decoder->bit_rate = (int)decoder->sync->frame.header.bitrate; } if (decoder->filter_func) { switch (decoder->filter_func(decoder->cb_data, &(decoder->sync->stream), &(decoder->sync->frame))) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: continue; case MAD_FLOW_CONTINUE: break; } } mad_synth_frame(&(decoder->sync->synth), &(decoder->sync->frame)); if (decoder->output_func) { switch (decoder->output_func(decoder, &decoder->sync->frame.header, &decoder->sync->synth.pcm)) { case MAD_FLOW_STOP: goto done; case MAD_FLOW_BREAK: goto fail; case MAD_FLOW_IGNORE: case MAD_FLOW_CONTINUE: break; } } } } while (decoder->sync->stream.error == MAD_ERROR_BUFLEN); fail: //result = -1; done: /* mad_synth_finish(synth); mad_frame_finish(frame); mad_stream_finish(stream); */ //return result; return decoder->sync->stream.this_frame - decoder->sync->stream.buffer; } # if defined(USE_ASYNC) static int run_async(struct mad_decoder *decoder) { pid_t pid; int ptoc[2], ctop[2], flags; if (pipe(ptoc) == -1) { return -1; } if (pipe(ctop) == -1) { close(ptoc[0]); close(ptoc[1]); return -1; } flags = fcntl(ptoc[0], F_GETFL); if (flags == -1 || fcntl(ptoc[0], F_SETFL, flags | O_NONBLOCK) == -1) { close(ctop[0]); close(ctop[1]); close(ptoc[0]); close(ptoc[1]); return -1; } pid = fork(); if (pid == -1) { close(ctop[0]); close(ctop[1]); close(ptoc[0]); close(ptoc[1]); return -1; } decoder->async.pid = pid; if (pid) { /* parent */ close(ptoc[0]); close(ctop[1]); decoder->async.in = ctop[0]; decoder->async.out = ptoc[1]; return 0; } /* child */ close(ptoc[1]); close(ctop[0]); decoder->async.in = ptoc[0]; decoder->async.out = ctop[1]; _exit(run_sync(decoder)); /* not reached */ return -1; } # endif /* * NAME: decoder->run() * DESCRIPTION: run the decoder thread either synchronously or asynchronously */ int mad_decoder_run(struct mad_decoder *decoder, enum mad_decoder_mode mode) { int result; int (*run)(struct mad_decoder *) = 0; switch (decoder->mode = mode) { case MAD_DECODER_MODE_SYNC: run = run_sync; break; case MAD_DECODER_MODE_ASYNC: # if defined(USE_ASYNC) run = run_async; # endif break; } if (run == 0) { return -1; } //decoder->sync = malloc(sizeof(*decoder->sync)); if (decoder->sync == 0) { return -1; } result = run(decoder); //free(decoder->sync); //decoder->sync = 0; return result; } /* * NAME: decoder->message() * DESCRIPTION: send a message to and receive a reply from the decoder process */ int mad_decoder_message(struct mad_decoder *decoder __unused, void *message __unused, unsigned int *len __unused) { # if defined(USE_ASYNC) if (decoder->mode != MAD_DECODER_MODE_ASYNC || send(decoder->async.out, message, *len) != MAD_FLOW_CONTINUE || receive(decoder->async.in, &message, len) != MAD_FLOW_CONTINUE) { return -1; } return 0; # else return -1; # endif } /* * This is the input callback. The purpose of this callback is to (re)fill * the stream buffer which is to be decoded. In this example, an entire file * has been mapped into memory, so we just call mad_stream_buffer() with the * address and length of the mapping. When this callback is called a second * time, we are finished decoding. */ static enum mad_flow input(void *data, struct mad_stream *stream) { struct buffer *buffer = data; if (!buffer->length) { return MAD_FLOW_STOP; } mad_stream_buffer(stream, buffer->start, buffer->length); buffer->length = 0; return MAD_FLOW_CONTINUE; } /* * The following utility routine performs simple rounding, clipping, and * scaling of MAD's high-resolution samples down to 16 bits. It does not * perform any dithering or noise shaping, which would be recommended to * obtain any exceptional audio quality. It is therefore not recommended to * use this routine if high-quality output is desired. */ static signed int scale(mad_fixed_t sample) { /* round */ sample += (1L << (MAD_F_FRACBITS - 16)); /* clip */ if (sample >= MAD_F_ONE) { sample = MAD_F_ONE - 1; } else if (sample < -MAD_F_ONE) { sample = -MAD_F_ONE; } /* quantize */ return sample >> (MAD_F_FRACBITS + 1 - 16); } /* * This is the output callback function. It is called after each frame of * MPEG audio data has been completely decoded. The purpose of this callback * is to output (or play) the decoded PCM audio. */ static enum mad_flow output(struct mad_decoder *decoder, struct mad_header const *header, struct mad_pcm *pcm) { int nchannels, nsamples; mad_fixed_t const *left_ch, *right_ch; /* pcm->samplerate contains the sampling frequency */ nchannels = pcm->channels; nsamples = pcm->length; left_ch = pcm->samples[0]; right_ch = pcm->samples[1]; //*pcm_out_len += 4608; /*store the last channel num and sr info */ if (decoder->last_ch_num != nchannels) { decoder->last_ch_num = nchannels; } if (decoder->last_sr != (int )pcm->samplerate) { decoder->last_sr = (int )pcm->samplerate; } (*(decoder->pcm_out_len)) += pcm->length * 2 * (header->mode > 0 ? 2 : 1);; if (decoder->sync->stream.muted_samples == 0) { decoder->sync->stream.muted_samples = pcm->samplerate * pcm->channels * MUTE_S; } if (decoder->sync->stream.muted_count < decoder->sync->stream.muted_samples) { memset(decoder->pcm_out_data, 0, 2 * nsamples); decoder->sync->stream.muted_count += nsamples; goto output1; } while (nsamples--) { signed int sample_l; signed int sample_r; /* output sample(s) in 16-bit signed little-endian PCM */ sample_l = scale(*left_ch++); //putchar((sample >> 0) & 0xff); //putchar((sample >> 8) & 0xff); decoder->pcm_out_data[0] = sample_l >> 0; decoder->pcm_out_data[1] = sample_l >> 8; decoder->pcm_out_data += 2; if (nchannels == 2) { sample_r = scale(*right_ch++); //putchar((sample >> 0) & 0xff); //putchar((sample >> 8) & 0xff); decoder->pcm_out_data[0] = sample_r >> 0; decoder->pcm_out_data[1] = sample_r >> 8; decoder->pcm_out_data += 2; } } output1: decoder->sync->stream.this_frame = decoder->sync->stream.next_frame; return MAD_FLOW_STOP; //return MAD_FLOW_CONTINUE; } /* * This is the error callback function. It is called whenever a decoding * error occurs. The error is indicated by stream->error; the list of * possible MAD_ERROR_* errors can be found in the mad.h (or stream.h) * header file. */ static enum mad_flow error(void *data __unused, struct mad_stream *stream, struct mad_frame *frame __unused) { //struct buffer *buffer = data; int tagsize; switch (stream->error) { case MAD_ERROR_LOSTSYNC: tagsize = id3_tag_query((char *)stream->this_frame, stream->bufend - stream->this_frame); if (tagsize > 0) { stream->skiplen = tagsize; audio_codec_print("id3 info, size = %d, just skip it!\n", tagsize); return MAD_FLOW_CONTINUE; } /* fall through */ default: break; } audio_codec_print("decoding error 0x%04x (%s) at byte offset %d\n", stream->error, mad_stream_errorstr(stream), (int)(stream->this_frame - stream->buffer)); /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */ if (stream->error == MAD_ERROR_BADBITALLOC) { return MAD_FLOW_IGNORE; } return MAD_FLOW_CONTINUE; } /* * This is the function called by main() above to perform all the decoding. * It instantiates a decoder object and configures it with the input, * output, and error callback functions above. A single call to * mad_decoder_run() continues until a callback function returns * MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and * signal an error). */ int audio_dec_decode( #ifndef _WIN32 audio_decoder_operations_t *adec_ops __unused, #endif char *outbuf, int *outlen, char *inbuf, int inlen/*unsigned char const *start, unsigned long length*/) { int result; struct mad_decoder *decoder = (struct mad_decoder *)adec_ops->pdecoder; struct buffer buffer; buffer.start = (unsigned char *)inbuf; buffer.length = inlen; /* initialize our private message structure */ decoder->pcm_out_data = outbuf; decoder->pcm_out_len = outlen; *(decoder->pcm_out_len) = 0; /* configure input, output, and error functions */ decoder->cb_data = &buffer; /* start decoding */ result = mad_decoder_run(decoder, MAD_DECODER_MODE_SYNC); /* release the decoder */ return result; } int audio_dec_init( #ifndef _WIN32 audio_decoder_operations_t *adec_ops #endif ) { //audio_codec_print("\n\n[%s]BuildDate--%s BuildTime--%s", __FUNCTION__, __DATE__, __TIME__); struct mad_decoder *decoder; decoder = malloc(sizeof (struct mad_decoder)); memset(decoder, 0, sizeof(struct mad_decoder)); mad_decoder_init(decoder, 0/*&buffer*/, input, 0 /* header */, 0 /* filter */, output, error, 0 /* message */); if (decoder->input_func == 0) { return -1; } if (decoder->error_func) { //error_func = decoder->error_func; //error_data = decoder->cb_data; } else { decoder->error_func = error_default; //error_data = &(decoder->bad_last_frame); } decoder->sync = malloc(sizeof(*decoder->sync)); //stream = &decoder.sync->stream; //frame = &decoder.sync->frame; //synth = &decoder.sync->synth; mad_stream_init(&decoder->sync->stream); mad_frame_init(&decoder->sync->frame); mad_synth_init(&decoder->sync->synth); mad_stream_options(&decoder->sync->stream, decoder->options); #ifndef _WIN32 /*[SE][BUG][SWPL-14828][chengshun.wang] decrease audio decode * in buffer size, avoid audio underrun */ adec_ops->nInBufSize = 1 * 1024; #endif decoder->sync->stream.muted_samples = 0; decoder->sync->stream.muted_count = 0; adec_ops->pdecoder = (struct mad_decoder * )decoder; audio_codec_print("libmad init ok!\n"); return 0; } #ifndef _WIN32 int audio_dec_getinfo(audio_decoder_operations_t *adec_ops, void *pAudioInfo) { struct mad_decoder *decoder = (struct mad_decoder *)(adec_ops->pdecoder); ((AudioInfo *)pAudioInfo)->bitrate = decoder->bit_rate; ((AudioInfo *)pAudioInfo)->error_num = decoder->error_nb_frames; ((AudioInfo *)pAudioInfo)->drop_num = decoder->droppped_nb_frames; ((AudioInfo *)pAudioInfo)->decode_num = decoder->decoded_nb_frames; if (decoder->last_ch_num <= 0 || decoder->last_sr <= 0) { return 0; } ((AudioInfo *)pAudioInfo)->channels = decoder->last_ch_num; ((AudioInfo *)pAudioInfo)->samplerate = decoder->last_sr; adec_ops->NchOriginal = decoder->last_ch_num; return 0; } #endif int audio_dec_release( #ifndef _WIN32 audio_decoder_operations_t *adec_ops __unused #endif ) { struct mad_decoder *decoder = (struct mad_decoder *)(adec_ops->pdecoder); mad_synth_finish(&decoder->sync->synth); mad_frame_finish(&decoder->sync->frame); mad_stream_finish(&decoder->sync->stream); free(decoder->sync); mad_decoder_finish(decoder); //stream->muted_samples = 0; //stream->muted_count = 0; free(decoder); audio_codec_print("libmad release ok!\n"); return 0; } // win test /* #ifdef _WIN32 char *filename = "mnjr.mp3"; char *filename2 = "mnjr.pcm"; FILE *fp; FILE *fp2; int main(int argc, char *argv[]) { char *outbuf; int *outlen; char *inbuf; int inlen; int size; int rlen; size = 0; inlen = 0; inbuf = (char *)malloc(50001); outbuf = (char *)malloc(1920000); outlen = (int *)malloc(5); //init fp = fopen(filename, "rb"); if (fp == NULL) { printf("open input file failed!\n"); return 0; } fp2 = fopen(filename2, "wb"); audio_dec_init(); do { //input if (size) { memmove(inbuf, inbuf + size, 20000 - size); rlen = size; } else { rlen = 20000; } inlen = fread(inbuf + 20000 - rlen, 1, rlen, fp); if (inlen == rlen) { inlen = 20000; } //decode size = audio_dec_decode( #ifndef _WIN32 adec_ops, #endif outbuf, outlen, inbuf, inlen); //output fwrite(outbuf, 1, *outlen, fp2); } while (inlen == 20000); //release audio_dec_release(); *pcm_out_data = NULL; *pcm_out_len = NULL; free(inbuf); free(outbuf); free(outlen); fclose(fp); fclose(fp2); inbuf = NULL; outbuf = NULL; outlen = NULL; return size; } #endif */