/* * aud_aux.c * * Copyright (C) Thomas Oestreich - June 2001 * Copyright (C) Nicolas LAURENT - August 2003 * * This file is part of transcode, a video stream processing tool * * transcode 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, or (at your option) * any later version. * * transcode 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 GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "transcode.h" #include "aud_aux.h" #include "libtc/libtc.h" #include #include #include #include #include #include #include #include #ifdef HAVE_LAME #ifdef HAVE_LAME_INC #include #else #include #endif #endif #ifdef HAVE_FFMPEG #include "libtc/tcavcodec.h" static AVCodec *mpa_codec = NULL; static AVCodecContext mpa_ctx; static char *mpa_buf = NULL; static int mpa_buf_ptr = 0; static int mpa_bytes_ps, mpa_bytes_pf; #endif /* * Capabilities: * * +-------------------------------+ * | Output | * +-------------------------------+ * | PCM | MP2 | MP3 | AC3 | * +---+-------+-------+-------+-------+-------+ * | I | PCM | X | X | X | X | * | n +-------+-------+-------+-------+-------+ * | p | MP2 | | X | | | * | u +-------+-------+-------+-------+-------+ * | t | MP3 | | | X | | * | +-------+-------+-------+-------+-------+ * | | AC3 | | | | X | * +---+---------------------------------------+ * */ /*----------------------------------------------------------------------------- G L O B A L V A R I A B L E S -----------------------------------------------------------------------------*/ #define MP3_CHUNK_SZ (2*1152) static int verbose_flag=TC_DEBUG; #define IS_AUDIO_MONO (avi_aud_chan == 1) #ifdef HAVE_LAME #define IS_VBR (lame_get_VBR(lgf) != vbr_off) #endif /* Output buffer */ #define OUTPUT_SIZE SIZE_PCM_FRAME static char *output = NULL; #ifdef HAVE_LAME static int output_len = 0; #endif /* Input buffer */ #define INPUT_SIZE SIZE_PCM_FRAME static char *input = NULL; #ifdef HAVE_LAME static int input_len = 0; #endif /* encoder */ static int (*tc_audio_encode_function)(char *, int, avi_t *)=NULL; #ifdef HAVE_LAME static lame_global_flags *lgf; #endif static int lame_flush=0; static int bitrate=0; /* output stream */ static avi_t *avifile2=NULL; static FILE *fd=NULL; static int is_pipe = 0; // AVI file information for subsequent calls of open routine: static int avi_aud_codec, avi_aud_bitrate; static long avi_aud_rate; static int avi_aud_chan, avi_aud_bits; /*----------------------------------------------------------------------------- P R O T O T Y P E S -----------------------------------------------------------------------------*/ static int tc_audio_init_ffmpeg(vob_t *vob, int o_codec); static int tc_audio_init_lame(vob_t *vob, int o_codec); static int tc_audio_init_raw(vob_t *vob); static int tc_audio_write(char *buffer, size_t size, avi_t *avifile); static int tc_audio_encode_ffmpeg(char *aud_buffer, int aud_size, avi_t *avifile); static int tc_audio_encode_mp3(char *aud_buffer, int aud_size, avi_t *avifile); static int tc_audio_pass_through(char *aud_buffer, int aud_size, avi_t *avifile); static int tc_audio_pass_through_ac3(char *aud_buffer, int aud_size, avi_t *avifile); static int tc_audio_pass_through_pcm(char *aud_buffer, int aud_size, avi_t *avifile); static int tc_audio_mute(char *aud_buffer, int aud_size, avi_t *avifile); #ifdef HAVE_LAME static char * lame_error2str(int error); static void no_debug(const char *format, va_list ap) {return;} static int tc_get_mp3_header(unsigned char* hbuf, int* chans, int* srate); #endif /** * Init Lame Encoder * * @param vob * * @return TC_EXPORT_OK or TC_EXPORT_ERROR */ static int tc_audio_init_lame(vob_t *vob, int o_codec) { static int initialized=0; int res = TC_EXPORT_ERROR; if (!initialized) if (verbose_flag & TC_DEBUG) tc_info("Audio: using new version"); if(initialized==0) { #ifdef HAVE_LAME int preset = 0; lgf=lame_init(); if(lgf<0) { tc_warn("Lame encoder init failed."); return(TC_EXPORT_ERROR); } if(!(verbose_flag & TC_DEBUG)) lame_set_msgf (lgf, no_debug); if(!(verbose_flag & TC_DEBUG)) lame_set_debugf(lgf, no_debug); if(!(verbose_flag & TC_DEBUG)) lame_set_errorf(lgf, no_debug); lame_set_bWriteVbrTag(lgf, 0); lame_set_quality(lgf, vob->mp3quality); /* Setting bitrate */ if(vob->a_vbr) { /* VBR */ lame_set_VBR(lgf, vob->a_vbr); /* 1 = best vbr q 6=~128k */ lame_set_VBR_q(lgf, vob->mp3quality); /* * if(vob->mp3bitrate>0) * lame_set_VBR_mean_bitrate_kbps( * lgf, * vob->mp3bitrate); */ } else { lame_set_VBR(lgf, 0); lame_set_brate(lgf, vob->mp3bitrate); } /* Playing with bitreservoir */ if(vob->bitreservoir == TC_FALSE) lame_set_disable_reservoir(lgf, 1); /* Mono / Sterero ? */ if (IS_AUDIO_MONO) { lame_set_num_channels(lgf, avi_aud_chan); lame_set_mode(lgf, MONO); } else { lame_set_num_channels(lgf, 2); lame_set_mode(lgf, JOINT_STEREO); } /* Overide defaults */ if (vob->mp3mode==1) lame_set_mode(lgf, STEREO); if (vob->mp3mode==2) lame_set_mode(lgf, MONO); /* sample rate */ lame_set_in_samplerate(lgf, vob->a_rate); lame_set_out_samplerate(lgf, avi_aud_rate); /* Optimisations */ if(tc_accel & AC_MMX) lame_set_asm_optimizations(lgf, MMX, 1); if(tc_accel & AC_3DNOW) lame_set_asm_optimizations(lgf, AMD_3DNOW, 1); if(tc_accel & AC_SSE) lame_set_asm_optimizations(lgf, SSE, 1); /* Preset stuff */ if (vob->lame_preset && strlen (vob->lame_preset)) { char *c = strchr (vob->lame_preset, ','); int fast = 0; if (c && *c && *(c+1)) { if (strcmp(c+1, "fast")) { *c = '\0'; fast = 1; } } if (strcmp (vob->lame_preset, "standard") == 0) { preset = fast?STANDARD_FAST:STANDARD; vob->a_vbr = 1; } else if (strcmp (vob->lame_preset, "medium") == 0) { preset = fast?MEDIUM_FAST:MEDIUM; vob->a_vbr = 1; } else if (strcmp (vob->lame_preset, "extreme") == 0) { preset = fast?EXTREME_FAST:EXTREME; vob->a_vbr = 1; } else if (strcmp (vob->lame_preset, "insane") == 0) { preset = INSANE; vob->a_vbr = 1; } else if ( atoi(vob->lame_preset) != 0) { vob->a_vbr = 1; preset = atoi(vob->lame_preset); avi_aud_bitrate = preset; } else tc_warn("Lame preset `%s' not supported. " "Falling back defaults.", vob->lame_preset); if (fast == 1) *c = ','; if (preset) { if (verbose_flag & TC_DEBUG) tc_info("Using Lame preset `%s'.", vob->lame_preset); lame_set_preset(lgf, preset); } } /* Init Lame ! */ lame_init_params(lgf); if(verbose_flag) tc_info("Audio: using lame-%s", get_lame_version()); if (verbose_flag & TC_DEBUG) { tc_info("Lame config: PCM -> %s", (o_codec==CODEC_MP3)?"MP3":"MP2"); tc_info(" bitrate : %d kbit/s", vob->mp3bitrate); tc_info(" ouput samplerate: %d Hz", (vob->mp3frequency>0)?vob->mp3frequency:vob->a_rate); } /* init lame encoder only on first call */ initialized = 1; res = TC_EXPORT_OK; #else /* HAVE_LAME */ tc_warn("No Lame support available!"); #endif /* HAVE_LAME */ } return res; } /** * Init FFMPEG AUDIO Encoder * * @param vob * * @return TC_EXPORT_OK or TC_EXPORT_ERROR */ static int tc_audio_init_ffmpeg(vob_t *vob, int o_codec) { int init_ret = TC_EXPORT_ERROR; #ifdef HAVE_FFMPEG unsigned long codeid = 0; int ret = 0; TC_INIT_LIBAVCODEC; switch (o_codec) { case 0x50: codeid = CODEC_ID_MP2; break; case 0x2000: codeid = CODEC_ID_AC3; break; default: tc_warn("cannot init ffmpeg with %x", o_codec); } //-- get it -- mpa_codec = avcodec_find_encoder(codeid); if (!mpa_codec) { tc_log_warn("encode_ffmpeg", "mpa codec not found !"); return(TC_EXPORT_ERROR); } // OPEN //-- set parameters (bitrate, channels and sample-rate) -- //-------------------------------------------------------- avcodec_get_context_defaults(&mpa_ctx); #if LIBAVCODEC_VERSION_MAJOR < 53 mpa_ctx.codec_type = CODEC_TYPE_AUDIO; #else mpa_ctx.codec_type = AVMEDIA_TYPE_AUDIO; #endif mpa_ctx.bit_rate = vob->mp3bitrate * 1000; // bitrate dest. mpa_ctx.channels = vob->dm_chan; // channels mpa_ctx.sample_rate = vob->a_rate; //-- open codec -- //---------------- TC_LOCK_LIBAVCODEC; ret = avcodec_open(&mpa_ctx, mpa_codec); TC_UNLOCK_LIBAVCODEC; if (ret < 0) { tc_warn("tc_audio_init_ffmpeg: could not open %s codec !", (codeid == CODEC_ID_MP2) ?"mpa" :"ac3"); return(TC_EXPORT_ERROR); } //-- bytes per sample and bytes per frame -- mpa_bytes_ps = mpa_ctx.channels * vob->dm_bits/8; mpa_bytes_pf = mpa_ctx.frame_size * mpa_bytes_ps; //-- create buffer to hold 1 frame -- mpa_buf = malloc(mpa_bytes_pf); mpa_buf_ptr = 0; init_ret = TC_EXPORT_OK; #else /* HAVE_FFMPEG */ tc_warn("No FFmpeg support available!"); #endif /* HAVE_FFMPEG */ return init_ret; } /** * Init audio encoder RAW -> * * * @param vob * * @return TC_EXPORT_OK or TC_EXPORT_ERROR */ static int tc_audio_init_raw(vob_t *vob) { if(vob->pass_flag & TC_AUDIO) { avi_t *avifile; avifile = AVI_open_input_file(vob->audio_in_file, 1); if(avifile != NULL) { /* set correct pass-through track: */ AVI_set_audio_track(avifile, vob->a_track); /* * small hack to fix incorrect samplerates caused by * transcode < 0.5.0-20011109 */ if (vob->mp3frequency==0) vob->mp3frequency=AVI_audio_rate(avifile); avi_aud_rate = vob->mp3frequency; avi_aud_chan = AVI_audio_channels(avifile); avi_aud_bits = AVI_audio_bits(avifile); avi_aud_codec = AVI_audio_format(avifile); avi_aud_bitrate = AVI_audio_mp3rate(avifile); AVI_close(avifile); } else { AVI_print_error("avi open error"); return(TC_EXPORT_ERROR); } } else tc_audio_encode_function=tc_audio_mute; return(TC_EXPORT_OK); } /** * init audio encoder * * @param vob * @param v is TC_DEBUG for verbose output or 0 * * @return TC_EXPORT_OK or TC_EXPORT_ERROR */ int tc_audio_init(vob_t *vob, int v) { int ret=TC_EXPORT_OK; int sample_size; verbose_flag=v; /* Default */ avi_aud_bitrate = vob->mp3bitrate; avi_aud_codec = vob->ex_a_codec; avi_aud_bits=vob->dm_bits; avi_aud_chan=vob->dm_chan; avi_aud_rate=(vob->mp3frequency != 0)?vob->mp3frequency:vob->a_rate; lame_flush=vob->encoder_flush; /* For encoding */ sample_size = avi_aud_bits * 8 * avi_aud_chan; /* * Sanity checks */ if((sample_size == 0) && (vob->im_a_codec != CODEC_NULL)) { tc_warn("Zero sample size detected for audio format `0x%x'. " "Muting.", vob->im_a_codec); tc_audio_encode_function=tc_audio_mute; return(TC_EXPORT_OK); } output = malloc (OUTPUT_SIZE); input = malloc (INPUT_SIZE); if (!output || !input) { tc_log_error(__FILE__, "(%s:%d) Out of memory", __FILE__, __LINE__); return (TC_EXPORT_ERROR); } /* paranoia... */ memset (output, 0, OUTPUT_SIZE); memset (input, 0, INPUT_SIZE); if (verbose_flag & TC_DEBUG) tc_info("Audio submodule in=0x%x out=0x%x", vob->im_a_codec, vob->ex_a_codec); switch(vob->im_a_codec) { case CODEC_PCM: switch(vob->ex_a_codec) { case CODEC_NULL: tc_audio_encode_function = tc_audio_mute; break; case CODEC_MP3: ret=tc_audio_init_lame(vob, vob->ex_a_codec); tc_audio_encode_function = tc_audio_encode_mp3; break; case CODEC_PCM: tc_info("PCM -> PCM"); /* adjust bitrate with magic ! */ avi_aud_bitrate=(vob->a_rate*4)/1000*8; tc_audio_encode_function = tc_audio_pass_through_pcm; break; case CODEC_MP2: tc_info("PCM -> MP2"); ret=tc_audio_init_ffmpeg(vob, vob->ex_a_codec); tc_audio_encode_function = tc_audio_encode_ffmpeg; break; case CODEC_AC3: tc_info("PCM -> AC3"); ret=tc_audio_init_ffmpeg(vob, vob->ex_a_codec); tc_audio_encode_function = tc_audio_encode_ffmpeg; break; default: tc_warn("Conversion not supported (in=0x%x out=0x%x)", vob->im_a_codec, vob->ex_a_codec); ret=TC_EXPORT_ERROR; break; } break; case CODEC_MP2: case CODEC_MP3: /* only pass through supported */ switch(vob->ex_a_codec) { case CODEC_NULL: tc_audio_encode_function = tc_audio_mute; break; case CODEC_MP2: case CODEC_MP3: tc_audio_encode_function = tc_audio_pass_through; break; default: tc_warn("Conversion not supported (in=x0%x out=x0%x)", vob->im_a_codec, vob->ex_a_codec); ret=TC_EXPORT_ERROR; break; } break; case CODEC_AC3: /* only pass through supported */ switch(vob->ex_a_codec) { case CODEC_NULL: tc_audio_encode_function = tc_audio_mute; break; case CODEC_AC3: tc_info("AC3->AC3"); if (vob->audio_file_flag) { tc_audio_encode_function = tc_audio_pass_through; } else { tc_audio_encode_function = tc_audio_pass_through_ac3; } /* *the bitrate can only be determined in the encoder * section. `bitrate_flags' will be set to 1 after * bitrate is determined. */ break; default: tc_warn("Conversion not supported (in=0x%x out=0x%x)", vob->im_a_codec, vob->ex_a_codec); ret=TC_EXPORT_ERROR; break; } break; case CODEC_NULL: /* no audio requested */ tc_audio_encode_function = tc_audio_mute; break; case CODEC_RAW: /* pass-through mode */ tc_audio_encode_function = tc_audio_pass_through; ret=tc_audio_init_raw(vob); break; default: tc_warn("Conversion not supported (in=x0%x out=x0%x)", vob->im_a_codec, vob->ex_a_codec); ret=TC_EXPORT_ERROR; break; } return(ret); } /** * open audio output file * * @param vob * @param avifile * * @return TC_EXPORT_OK or TC_EXPORT_ERROR */ int tc_audio_open(vob_t *vob, avi_t *avifile) { if (tc_audio_encode_function != tc_audio_mute) { if(vob->audio_file_flag) { if(! fd) { if (vob->audio_out_file[0] == '|') { fd = popen(vob->audio_out_file+1, "w"); if (! fd) { tc_warn("Cannot popen() audio " "file `%s'", vob->audio_out_file+1); return(TC_EXPORT_ERROR); } is_pipe = 1; } else { fd = fopen(vob->audio_out_file, "w"); if (! fd) { tc_warn("Cannot open() audio " "file `%s'", vob->audio_out_file); return(TC_EXPORT_ERROR); } } } if (verbose_flag & TC_DEBUG) tc_info("Sending audio output to %s", vob->audio_out_file); } else { if(avifile==NULL) { tc_audio_encode_function = tc_audio_mute; tc_info("No option `-m' found. Muting sound."); return(TC_EXPORT_OK); } AVI_set_audio(avifile, avi_aud_chan, avi_aud_rate, avi_aud_bits, avi_aud_codec, avi_aud_bitrate); AVI_set_audio_vbr(avifile, vob->a_vbr); if (vob->avi_comment_fd > 0) AVI_set_comment_fd(avifile, vob->avi_comment_fd); if(avifile2 == NULL) avifile2 = avifile; /* save for close */ if (verbose_flag & TC_DEBUG) tc_info("AVI stream: format=0x%x, rate=%ld Hz, " "bits=%d, channels=%d, bitrate=%d", avi_aud_codec, avi_aud_rate, avi_aud_bits, avi_aud_chan, avi_aud_bitrate); } } return(TC_EXPORT_OK); } /** * Write audio data to output stream */ static int tc_audio_write(char *buffer, size_t size, avi_t *avifile) { if (fd != NULL) { if (fwrite(buffer, size, 1, fd) != 1) { tc_warn("Audio file write error (errno=%d) [%s].", errno, strerror(errno)); return(TC_EXPORT_ERROR); } } else { if (AVI_write_audio(avifile, buffer, size) < 0) { AVI_print_error("AVI file audio write error"); return(TC_EXPORT_ERROR); } } return(TC_EXPORT_OK); } /** * encode audio frame in MP3 format * * @param aud_buffer is the input buffer ? * @param aud_size is the input buffer length * @param avifile is the output stream * * @return * * How this code works: * * We always encode raw audio chunks which are MP3_CHUNK_SZ (==2304) * bytes large. `input' contains the raw audio buffer contains * the encoded audio * * It is possible (very likely) that lame cannot produce a valid mp3 * chunk per "audio frame" so we do not write out any compressed audio. * We need to buffer the not consumed input audio where another 2304 * bytes chunk won't fit in AND we need to buffer the already encoded * but not enough audio. * * To find out how much we actually need to encode we decode the mp3 * header of the recently encoded audio chunk and read out the actual * length. * * Then we write the audio. There can either be more than one valid mp3 * frame in buffer and/or still enough raw data left to encode one. * * Easy, eh? -- tibit. */ static int tc_audio_encode_mp3(char *aud_buffer, int aud_size, avi_t *avifile) { #ifdef HAVE_LAME int outsize=0; int count=0; /* * Apend the new incoming audio to the already available but not yet * consumed. */ ac_memcpy (input+input_len, aud_buffer, aud_size); input_len += aud_size; if (verbose_flag & TC_DEBUG) tc_info("audio_encode_mp3: input buffer size=%d", input_len); /* * As long as lame doesn't return encoded data (lame needs to fill its * internal buffers) AND as long as there is enough input data left. */ while(input_len >= MP3_CHUNK_SZ) { if(IS_AUDIO_MONO) { outsize = lame_encode_buffer( lgf, (short int *)(input+count*MP3_CHUNK_SZ), (short int *)(input+count*MP3_CHUNK_SZ), MP3_CHUNK_SZ/2, output+output_len, OUTPUT_SIZE - output_len); } else { outsize = lame_encode_buffer_interleaved( lgf, (short int *) (input+count*MP3_CHUNK_SZ), MP3_CHUNK_SZ/4, output + output_len, OUTPUT_SIZE - output_len); } if(outsize < 0) { tc_warn("Lame encoding error: (%s)", lame_error2str(outsize)); return(TC_EXPORT_ERROR); } output_len += outsize; input_len -= MP3_CHUNK_SZ; ++count; if (verbose_flag & TC_DEBUG) tc_info("Encoding: count=%d outsize=%d output_len=%d " "consumed=%d", count, outsize, output_len, count*MP3_CHUNK_SZ); } /* Update input */ memmove(input, input+count*MP3_CHUNK_SZ, input_len); if (verbose_flag & TC_DEBUG) tc_info("output_len=%d input_len=%d count=%d", output_len, input_len, count); /* If we don't have any output data, there's nothing to do */ if (output_len == 0) { return(TC_EXPORT_OK); } /* * Now, it's time to write mp3 data to output stream... */ if (IS_VBR) { int offset=0; int size; /* * In VBR mode, we should write _complete_ chunk. And their * size may change from one to other... So we should analyse * each one and write it if enough data is avaible. */ if (verbose_flag & TC_DEBUG) tc_info("Writing... (output_len=%d)\n", output_len); while((size=tc_get_mp3_header(output+offset, NULL, NULL)) > 0) { if (size > output_len) break; if (verbose_flag & TC_DEBUG) tc_info("Writing chunk of size=%d", size); tc_audio_write(output+offset, size, avifile); offset += size; output_len -= size; } memmove(output, output+offset, output_len); if (verbose_flag & TC_DEBUG) tc_info("Writing OK (output_len=%d)", output_len); } else { /* * in CBR mode, write our data in simplest way. * Thinking too much about chunk will break audio playback * on archos Jukebox Multimedia... */ tc_audio_write(output, output_len, avifile); output_len=0; } return(TC_EXPORT_OK); #else // HAVE_LAME tc_warn("No Lame support available!"); return(TC_EXPORT_ERROR); #endif } static int tc_audio_encode_ffmpeg(char *aud_buffer, int aud_size, avi_t *avifile) { #ifdef HAVE_FFMPEG int in_size, out_size; char *in_buf; //-- input buffer and amount of bytes -- in_size = aud_size; in_buf = aud_buffer; //-- any byte in mpa-buffer left from past call ? -- //-------------------------------------------------- if (mpa_buf_ptr > 0) { int bytes_needed, bytes_avail; bytes_needed = mpa_bytes_pf - mpa_buf_ptr; bytes_avail = in_size; //-- complete frame -> encode -- //------------------------------ if ( bytes_avail >= bytes_needed ) { ac_memcpy(&mpa_buf[mpa_buf_ptr], in_buf, bytes_needed); TC_LOCK_LIBAVCODEC; out_size = avcodec_encode_audio(&mpa_ctx, (unsigned char *)output, OUTPUT_SIZE, (short *)mpa_buf); TC_UNLOCK_LIBAVCODEC; tc_audio_write(output, out_size, avifile); in_size -= bytes_needed; in_buf += bytes_needed; mpa_buf_ptr = 0; } //-- incomplete frame -> append bytes to mpa-buffer and return -- //--------------------------------------------------------------- else { ac_memcpy(&mpa_buf[mpa_buf_ptr], aud_buffer, bytes_avail); mpa_buf_ptr += bytes_avail; return (0); } } //bytes availabe from last call? //-- encode only as much "full" frames as available -- //---------------------------------------------------- while (in_size >= mpa_bytes_pf) { TC_LOCK_LIBAVCODEC; out_size = avcodec_encode_audio(&mpa_ctx, (unsigned char *)output, OUTPUT_SIZE, (short *)in_buf); TC_UNLOCK_LIBAVCODEC; tc_audio_write(output, out_size, avifile); in_size -= mpa_bytes_pf; in_buf += mpa_bytes_pf; } //-- hold rest of bytes in mpa-buffer -- //-------------------------------------- if (in_size > 0) { mpa_buf_ptr = in_size; ac_memcpy(mpa_buf, in_buf, mpa_buf_ptr); } return(TC_EXPORT_OK); #else // HAVE_FFMPEG tc_warn("No FFMPEG support available!"); return(TC_EXPORT_ERROR); #endif } static int tc_audio_pass_through_ac3(char *aud_buffer, int aud_size, avi_t *avifile) { if(bitrate == 0) { int i; uint16_t sync_word = 0; /* try to determine bitrate from audio frame: */ for(i=0;i> 1; if (ratecode < sizeof(bitrates)/sizeof(*bitrates)) bitrate = bitrates[ratecode]; break; } } /* assume bitrate > 0 is OK. */ if (bitrate > 0) { AVI_set_audio_bitrate(avifile, bitrate); if (verbose_flag & TC_DEBUG) tc_info("bitrate %d kBits/s", bitrate); } } return(tc_audio_write(aud_buffer, aud_size, avifile)); } /** * */ static int tc_audio_pass_through_pcm(char *aud_buffer, int aud_size, avi_t *avifile) { #ifdef WORDS_BIGENDIAN int i; char tmp; for(i=0; i 0) { tc_audio_write(output, outsize, avifile2); } } #endif } if(fd) { if (is_pipe) pclose(fd); else fclose(fd); fd=NULL; } avifile2 = NULL; return(TC_EXPORT_OK); } int tc_audio_stop() { if (input) { free(input); input = NULL; } if (output) { free(output); output = NULL; } #ifdef HAVE_LAME if (tc_audio_encode_function == tc_audio_encode_mp3) lame_close(lgf); #endif #ifdef HAVE_FFMPEG if (tc_audio_encode_function == tc_audio_encode_ffmpeg) { //-- release encoder -- if (mpa_codec) avcodec_close(&mpa_ctx); //-- cleanup buffer resources -- if (mpa_buf) free(mpa_buf); mpa_buf = NULL; mpa_buf_ptr = 0; } #endif return(0); } #ifdef HAVE_LAME /** * */ static char * lame_error2str(int error) { switch (error) { case -1: return "-1: mp3buf was too small"; case -2: return "-2: malloc() problem"; case -3: return "-3: lame_init_params() not called"; case -4: return "-4: psycho acoustic problems"; case -5: return "-5: ogg cleanup encoding error"; case -6: return "-6: ogg frame encoding error"; default: return "Unknown lame error"; } } // from mencoder //----------------------- mp3 audio frame header parser ----------------------- static int tabsel_123[2][3][16] = { { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0} }, { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0}, {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0}, {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0} } }; static long freqs[9] = { 44100, 48000, 32000, 22050, 24000, 16000 , 11025 , 12000 , 8000 }; /* * return frame size or -1 (bad frame) */ static int tc_get_mp3_header(unsigned char* hbuf, int* chans, int* srate){ int stereo, ssize, crc, lsf, mpeg25, framesize; int padding, bitrate_index, sampling_frequency; unsigned long newhead = hbuf[0] << 24 | hbuf[1] << 16 | hbuf[2] << 8 | hbuf[3]; // head_check: if( (newhead & 0xffe00000) != 0xffe00000 || (newhead & 0x0000fc00) == 0x0000fc00){ //tc_log_warn(__FILE__, "head_check failed"); return -1; } if((4-((newhead>>17)&3))!=3){ tc_warn("not layer-3"); return -1; } if( newhead & ((long)1<<20) ) { lsf = (newhead & ((long)1<<19)) ? 0x0 : 0x1; mpeg25 = 0; } else { lsf = 1; mpeg25 = 1; } if(mpeg25) sampling_frequency = 6 + ((newhead>>10)&0x3); else sampling_frequency = ((newhead>>10)&0x3) + (lsf*3); if(sampling_frequency>8){ tc_warn("invalid sampling_frequency"); return -1; // valid: 0..8 } crc = ((newhead>>16)&0x1)^0x1; bitrate_index = ((newhead>>12)&0xf); padding = ((newhead>>9)&0x1); // fr->extension = ((newhead>>8)&0x1); // fr->mode = ((newhead>>6)&0x3); // fr->mode_ext = ((newhead>>4)&0x3); // fr->copyright = ((newhead>>3)&0x1); // fr->original = ((newhead>>2)&0x1); // fr->emphasis = newhead & 0x3; stereo = ( (((newhead>>6)&0x3)) == 3) ? 1 : 2; if(!bitrate_index){ tc_warn("Free format not supported."); return -1; } if(lsf) ssize = (stereo == 1) ? 9 : 17; else ssize = (stereo == 1) ? 17 : 32; if(crc) ssize += 2; framesize = tabsel_123[lsf][2][bitrate_index] * 144000; if(!framesize){ tc_warn("invalid framesize/bitrate_index"); return -1; // valid: 1..14 } framesize /= freqs[sampling_frequency]<MAXFRAMESIZE) return FALSE; if(srate) *srate = freqs[sampling_frequency]; if(chans) *chans = stereo; return framesize; } #endif // HAVE_LAME