////////////////////////////////////////////////////////////////////// // Init - initialized or reiniyialized encoder SDK with given input // and output settings ////////////////////////////////////////////////////////////////////// HRESULT CEncoder::Init() { CAutoLock l(&m_lock); m_outOffset = 0; m_outReadOffset = 0; m_bFinished = FALSE; m_frameCount = 0; if (!pgf) { if (!m_bInpuTypeSet || !m_bOutpuTypeSet) return E_UNEXPECTED; // Init Lame library // note: newer, safer interface which doesn't // allow or require direct access to 'gf' struct is being written // see the file 'API' included with LAME. if (pgf = lame_init()) { lame_set_num_channels(pgf, m_wfex.nChannels); lame_set_in_samplerate(pgf, m_wfex.nSamplesPerSec); lame_set_out_samplerate(pgf, m_mabsi.dwSampleRate); if ((lame_get_out_samplerate(pgf) >= 32000) && (m_mabsi.dwBitrate < 32)) lame_set_brate(pgf, 32); else lame_set_brate(pgf, m_mabsi.dwBitrate); lame_set_VBR(pgf, m_mabsi.vmVariable); lame_set_VBR_min_bitrate_kbps(pgf, m_mabsi.dwVariableMin); lame_set_VBR_max_bitrate_kbps(pgf, m_mabsi.dwVariableMax); lame_set_copyright(pgf, m_mabsi.bCopyright); lame_set_original(pgf, m_mabsi.bOriginal); lame_set_error_protection(pgf, m_mabsi.bCRCProtect); lame_set_bWriteVbrTag(pgf, m_mabsi.dwXingTag); lame_set_strict_ISO(pgf, m_mabsi.dwStrictISO); lame_set_VBR_hard_min(pgf, m_mabsi.dwEnforceVBRmin); if (lame_get_num_channels(pgf) == 2 && !m_mabsi.bForceMono) { //int act_br = pgf->VBR ? pgf->VBR_min_bitrate_kbps + pgf->VBR_max_bitrate_kbps / 2 : pgf->brate; // Disabled. It's for user's consideration now //int rel = pgf->out_samplerate / (act_br + 1); //pgf->mode = rel < 200 ? m_mabsi.ChMode : JOINT_STEREO; lame_set_mode(pgf, m_mabsi.ChMode); } else lame_set_mode(pgf, MONO); if (lame_get_mode(pgf) == JOINT_STEREO) lame_set_force_ms(pgf, m_mabsi.dwForceMS); else lame_set_force_ms(pgf, 0); // pgf->mode_fixed = m_mabsi.dwModeFixed; if (m_mabsi.dwVoiceMode != 0) { lame_set_lowpassfreq(pgf,12000); ///pgf->VBR_max_bitrate_kbps = 160; } if (m_mabsi.dwKeepAllFreq != 0) { ///pgf->lowpassfreq = -1; ///pgf->highpassfreq = -1; /// not available anymore } lame_set_quality(pgf, m_mabsi.dwQuality); lame_set_VBR_q(pgf, m_mabsi.dwVBRq); lame_init_params(pgf); // encoder delay compensation { int const nch = lame_get_num_channels(pgf); short * start_padd = (short *)calloc(48, nch * sizeof(short)); int out_bytes = 0; if (nch == 2) out_bytes = lame_encode_buffer_interleaved(pgf, start_padd, 48, m_outFrameBuf, OUT_BUFFER_SIZE); else out_bytes = lame_encode_buffer(pgf, start_padd, start_padd, 48, m_outFrameBuf, OUT_BUFFER_SIZE); if (out_bytes > 0) m_outOffset += out_bytes; free(start_padd); } return S_OK; } return E_FAIL; } return S_OK; }
////////////////////////////////////////////////////////////////////// // Encode - encodes data placed on pdata and returns // the number of processed bytes ////////////////////////////////////////////////////////////////////// int CEncoder::Encode(const short * pdata, int data_size) { CAutoLock l(&m_lock); if (!pgf || !m_outFrameBuf || !pdata || data_size < 0 || (data_size & (sizeof(short) - 1))) return -1; // some data left in the buffer, shift to start if (m_outReadOffset > 0) { if (m_outOffset > m_outReadOffset) memmove(m_outFrameBuf, m_outFrameBuf + m_outReadOffset, m_outOffset - m_outReadOffset); m_outOffset -= m_outReadOffset; } m_outReadOffset = 0; m_bFinished = FALSE; int bytes_processed = 0; int const nch = lame_get_num_channels(pgf); while (1) { int nsamples = (data_size - bytes_processed) / (sizeof(short) * nch); if (nsamples <= 0) break; if (nsamples > 1152) nsamples = 1152; if (m_outOffset >= OUT_BUFFER_MAX) break; int out_bytes = 0; if (nch == 2) out_bytes = lame_encode_buffer_interleaved( pgf, (short *)(pdata + (bytes_processed / sizeof(short))), nsamples, m_outFrameBuf + m_outOffset, OUT_BUFFER_SIZE - m_outOffset); else out_bytes = lame_encode_buffer( pgf, pdata + (bytes_processed / sizeof(short)), pdata + (bytes_processed / sizeof(short)), nsamples, m_outFrameBuf + m_outOffset, OUT_BUFFER_SIZE - m_outOffset); if (out_bytes < 0) return -1; m_outOffset += out_bytes; bytes_processed += nsamples * nch * sizeof(short); } return bytes_processed; }
/*------------------------------------------------------------------------------ * Write data to the encoder *----------------------------------------------------------------------------*/ unsigned int LameLibEncoder :: write ( const void * buf, unsigned int len ) throw ( Exception ) { if ( !isOpen() ) { return 0; } unsigned int bitsPerSample = getInBitsPerSample(); unsigned int channels = getInChannel(); if ( channels != 1 && channels != 2 ) { throw Exception( __FILE__, __LINE__, "unsupported number of channels for the encoder", channels ); } unsigned int sampleSize = (bitsPerSample / 8) * channels; unsigned char * b = (unsigned char*) buf; unsigned int processed = len - (len % sampleSize); unsigned int nSamples = processed / sampleSize; short int leftBuffer[nSamples]; short int rightBuffer[nSamples]; if ( bitsPerSample == 8 ) { conv8( b, processed, leftBuffer, rightBuffer, channels); } else if ( bitsPerSample == 16 ) { conv16( b, processed, leftBuffer, rightBuffer, channels); } else { throw Exception( __FILE__, __LINE__, "unsupported number of bits per sample for the encoder", bitsPerSample ); } // data chunk size estimate according to lame documentation unsigned int mp3Size = (unsigned int) (1.25 * nSamples + 7200); unsigned char mp3Buf[mp3Size]; int ret; ret = lame_encode_buffer( lameGlobalFlags, leftBuffer, channels == 2 ? rightBuffer : leftBuffer, nSamples, mp3Buf, mp3Size ); if ( ret < 0 ) { reportEvent( 3, "lame encoding error", ret); return 0; } unsigned int written = sink->write( mp3Buf, ret); // just let go data that could not be written if ( written < (unsigned int) ret ) { reportEvent( 2, "couldn't write all from encoder to underlying sink", ret - written); } return processed; }
/*------------------------------------------------------------------------------ * Write data to the encoder *----------------------------------------------------------------------------*/ unsigned int LameLibEncoder :: write ( const void * buf, unsigned int len ) throw ( Exception ) { if ( !isOpen() ) { return 0; } unsigned int bitsPerSample = getInBitsPerSample(); unsigned int inChannels = getInChannel(); unsigned int sampleSize = (bitsPerSample / 8) * inChannels; unsigned char * b = (unsigned char*) buf; unsigned int processed = len - (len % sampleSize); unsigned int nSamples = processed / sampleSize; short int * leftBuffer = new short int[nSamples]; short int * rightBuffer = new short int[nSamples]; if ( bitsPerSample == 8 ) { Util::conv8( b, processed, leftBuffer, rightBuffer, inChannels); } else if ( bitsPerSample == 16 ) { Util::conv16( b, processed, leftBuffer, rightBuffer, inChannels, isInBigEndian()); } else { delete[] leftBuffer; delete[] rightBuffer; throw Exception( __FILE__, __LINE__, "unsupported number of bits per sample for the encoder", bitsPerSample ); } // data chunk size estimate according to lame documentation // NOTE: mp3Size is calculated based on the number of input channels // which may be bigger than need, as output channels can be less unsigned int mp3Size = (unsigned int) (1.25 * nSamples + 7200); unsigned char * mp3Buf = new unsigned char[mp3Size]; int ret; ret = lame_encode_buffer( lameGlobalFlags, leftBuffer, inChannels == 2 ? rightBuffer : leftBuffer, nSamples, mp3Buf, mp3Size ); delete[] leftBuffer; delete[] rightBuffer; if ( ret < 0 ) { reportEvent( 3, "lame encoding error", ret); delete[] mp3Buf; return 0; } unsigned int written = sink->write( mp3Buf, ret); delete[] mp3Buf; // just let go data that could not be written if ( written < (unsigned int) ret ) { reportEvent( 2, "couldn't write all from encoder to underlying sink", ret - written); } return processed; }
static switch_status_t shout_file_write(switch_file_handle_t *handle, void *data, size_t *len) { shout_context_t *context; int rlen = 0; int16_t *audio = data; size_t nsamples = *len; if (!handle) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error no handle\n"); return SWITCH_STATUS_FALSE; } if (!(context = handle->private_info)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error no context\n"); return SWITCH_STATUS_FALSE; } if (context->err) { return SWITCH_STATUS_FALSE; } if (context->shout && !context->shout_init) { if (!context->gfp) { return SWITCH_STATUS_FALSE; } context->shout_init++; if (shout_open(context->shout) != SHOUTERR_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening stream: %s\n", shout_get_error(context->shout)); context->err++; return SWITCH_STATUS_FALSE; } launch_write_stream_thread(context); } if (handle->handler && context->audio_mutex) { switch_mutex_lock(context->audio_mutex); if (context->audio_buffer) { if (!switch_buffer_write(context->audio_buffer, data, (nsamples * sizeof(int16_t) * handle->channels))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Buffer error\n"); context->err++; } } else { context->err++; } switch_mutex_unlock(context->audio_mutex); if (context->err) { return SWITCH_STATUS_FALSE; } handle->sample_count += *len; return SWITCH_STATUS_SUCCESS; } if (!context->lame_ready) { lame_init_params(context->gfp); lame_print_config(context->gfp); context->lame_ready = 1; } if (context->mp3buflen < nsamples * 4) { context->mp3buflen = nsamples * 4; context->mp3buf = switch_core_alloc(context->memory_pool, context->mp3buflen); } if (handle->channels == 2) { switch_size_t i, j = 0; if (context->llen < nsamples) { context->l = switch_core_alloc(context->memory_pool, nsamples * 2); context->r = switch_core_alloc(context->memory_pool, nsamples * 2); context->llen = context->rlen = nsamples; } for (i = 0; i < nsamples; i++) { context->l[i] = audio[j++]; context->r[i] = audio[j++]; } if ((rlen = lame_encode_buffer(context->gfp, context->l, context->r, nsamples, context->mp3buf, context->mp3buflen)) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MP3 encode error %d!\n", rlen); return SWITCH_STATUS_FALSE; } } else if (handle->channels == 1) { if ((rlen = lame_encode_buffer(context->gfp, audio, NULL, nsamples, context->mp3buf, context->mp3buflen)) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MP3 encode error %d!\n", rlen); return SWITCH_STATUS_FALSE; } } else { rlen = 0; } if (rlen) { int ret = fwrite(context->mp3buf, 1, rlen, context->fp); if (ret < 0) { return SWITCH_STATUS_FALSE; } } handle->sample_count += *len; return SWITCH_STATUS_SUCCESS; }
//core function to encide WAV to MP3, relying on LAME library void encode(char* wavFilePath, char* mp3FilePath) { FILE* wavFile = fopen(wavFilePath, "rb"); FILE* mp3File = fopen(mp3FilePath, "wb+"); int readPCMSampleCount; short int pcmBuffer[PCM_BUF_SIZE]; unsigned char mp3Buffer[MP3_BUF_SIZE]; unsigned short channel; unsigned long sampleRate; unsigned short blockAlign; lame_t lame = lame_init(); if((wavFile == NULL) || (mp3File == NULL)) { printErrorMessage(FILE_IO_EXCEPTION); return; } if(lame == NULL) { printErrorMessage(LAME_API_ERROR); return; } //Set number of channels else if(fseek(wavFile, 22, SEEK_SET) != 0) { printErrorMessage(FILE_IO_EXCEPTION); return; } else if(fread(&channel, 2, 1, wavFile) < 1) { printErrorMessage(FILE_IO_EXCEPTION); return; } else { lame_set_num_channels(lame, channel); lame_set_mode(lame, (channel == 1) ? MONO : JOINT_STEREO); } //Set number of sample rate if(fseek(wavFile, 24, SEEK_SET) != 0) { printErrorMessage(FILE_IO_EXCEPTION); return; } else if(fread(&sampleRate, 4, 1, wavFile) < 1) { printErrorMessage(FILE_IO_EXCEPTION); return; } else { lame_set_in_samplerate(lame, sampleRate); lame_set_out_samplerate(lame, sampleRate); } //Set block align (byte/sample) if(fseek(wavFile, 32, SEEK_SET) != 0) { printErrorMessage(FILE_IO_EXCEPTION); return; } else if(fread(&blockAlign, 4, 1, wavFile) < 1) { printErrorMessage(FILE_IO_EXCEPTION); return; } //Look for data chank in the WAV file if(fseek(wavFile, 36, SEEK_SET) != 0) { printErrorMessage(FILE_IO_EXCEPTION); return; } else { char data[5]; data[4] = '\0'; while(fread(data, 4, 1, wavFile) == 1) { if(strcmp(data, "data") != 0) { //Search data chank by 1 byte fseek(wavFile, -3, SEEK_CUR); continue; } else if(fseek(wavFile, 4, SEEK_CUR)) { //data chank was found, then skip next 4 byte(indicating data size) to proceed printErrorMessage(FILE_IO_EXCEPTION); return; } else { //Now we are pointing the head of the PCM data, let's proceed break; } } //If data chank cannot be detected if(feof(wavFile)) { printErrorMessage(NOT_WAV_HEADER); return; } } //Encoding conficuration with "good" level quality lame_set_quality(lame, 5); lame_set_VBR(lame, vbr_default); lame_set_VBR_q(lame, 5); if(lame_init_params(lame) == -1) { printErrorMessage(LAME_API_ERROR); return; } //Perfoem encoding do { int encodedSampleCount; readPCMSampleCount = fread(pcmBuffer, blockAlign, PCM_BUF_SIZE / blockAlign, wavFile); if(readPCMSampleCount != 0) { if(channel == 1) { //For monoral case short int pcmBufferRight[PCM_BUF_SIZE]; short int pcmBufferLeft[PCM_BUF_SIZE]; int i; for(i = 0; i < PCM_BUF_SIZE; i++) { pcmBufferRight[i] = pcmBuffer[i]; pcmBufferLeft[i] = pcmBuffer[i]; } encodedSampleCount = lame_encode_buffer(lame, pcmBufferLeft, pcmBufferRight, readPCMSampleCount, mp3Buffer, MP3_BUF_SIZE); } else { //For stereo case encodedSampleCount = lame_encode_buffer_interleaved(lame, pcmBuffer, readPCMSampleCount, mp3Buffer, MP3_BUF_SIZE); } } else { encodedSampleCount = lame_encode_flush(lame, mp3Buffer, MP3_BUF_SIZE); } if(encodedSampleCount < 0) { printErrorMessage(LAME_API_ERROR); } else { fwrite(mp3Buffer, encodedSampleCount, 1, mp3File); } } while(readPCMSampleCount != 0); lame_close(lame); fclose(wavFile); fclose(mp3File); }
static inline void free_context(shout_context_t *context) { int ret; if (context) { switch_mutex_lock(context->audio_mutex); context->err++; switch_mutex_unlock(context->audio_mutex); if (context->stream_url) { int sanity = 0; while (context->thread_running) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for stream to terminate: %s\n", context->stream_url); switch_yield(500000); if (++sanity > 10) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Giving up waiting for stream to terminate: %s\n", context->stream_url); break; } } } switch_thread_rwlock_wrlock(context->rwlock); if (context->mh) { mpg123_close(context->mh); mpg123_delete(context->mh); } if (context->fp) { unsigned char mp3buffer[20480]; int len; int16_t blank[2048] = { 0 }, *r = NULL; if (context->channels == 2) { r = blank; } len = lame_encode_buffer(context->gfp, blank, r, sizeof(blank) / 2, mp3buffer, sizeof(mp3buffer)); if (len) { ret = fwrite(mp3buffer, 1, len, context->fp); } while ((len = lame_encode_flush(context->gfp, mp3buffer, sizeof(mp3buffer))) > 0) { ret = fwrite(mp3buffer, 1, len, context->fp); if (ret < 0) { break; } } lame_mp3_tags_fid(context->gfp, context->fp); fclose(context->fp); context->fp = NULL; } if (context->shout) { if (context->gfp) { unsigned char mp3buffer[8192]; int len; int16_t blank[2048] = { 0 }, *r = NULL; if (context->channels == 2) { r = blank; } len = lame_encode_buffer(context->gfp, blank, r, sizeof(blank) / 2, mp3buffer, sizeof(mp3buffer)); if (len) { ret = shout_send(context->shout, mp3buffer, len); if (ret == SHOUTERR_SUCCESS) { shout_sync(context->shout); } } while ((len = lame_encode_flush(context->gfp, mp3buffer, sizeof(mp3buffer))) > 0) { ret = shout_send(context->shout, mp3buffer, len); if (ret != SHOUTERR_SUCCESS) { break; } else { shout_sync(context->shout); } } } shout_close(context->shout); context->shout = NULL; } if (context->gfp) { lame_close(context->gfp); context->gfp = NULL; } if (context->audio_buffer) { switch_buffer_destroy(&context->audio_buffer); } switch_mutex_destroy(context->audio_mutex); switch_thread_rwlock_unlock(context->rwlock); switch_thread_rwlock_destroy(context->rwlock); } }
static void *SWITCH_THREAD_FUNC write_stream_thread(switch_thread_t *thread, void *obj) { shout_context_t *context = (shout_context_t *) obj; switch_thread_rwlock_rdlock(context->rwlock); if (context->thread_running) { context->thread_running++; } else { switch_thread_rwlock_unlock(context->rwlock); return NULL; } if (!context->lame_ready) { lame_init_params(context->gfp); lame_print_config(context->gfp); context->lame_ready = 1; } while (!context->err && context->thread_running) { unsigned char mp3buf[20480] = ""; int16_t audio[9600] = { 0 }; switch_size_t audio_read = 0; int rlen = 0; long ret = 0; switch_mutex_lock(context->audio_mutex); if (context->audio_buffer) { audio_read = switch_buffer_read(context->audio_buffer, audio, sizeof(audio)); } else { context->err++; } switch_mutex_unlock(context->audio_mutex); error_check(); if (!audio_read) { audio_read = sizeof(audio); memset(audio, 255, sizeof(audio)); } if (context->channels == 2) { int16_t l[4800] = { 0 }; int16_t r[4800] = { 0 }; int j = 0; switch_size_t i; for (i = 0; i < audio_read / 4; i++) { l[i] = audio[j++]; r[i] = audio[j++]; } if ((rlen = lame_encode_buffer(context->gfp, l, r, audio_read / 4, mp3buf, sizeof(mp3buf))) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MP3 encode error %d!\n", rlen); goto error; } } else if (context->channels == 1) { if ((rlen = lame_encode_buffer(context->gfp, (void *) audio, NULL, audio_read / sizeof(int16_t), mp3buf, sizeof(mp3buf))) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MP3 encode error %d!\n", rlen); goto error; } } if (rlen) { ret = shout_send(context->shout, mp3buf, rlen); if (ret != SHOUTERR_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Send error: %s\n", shout_get_error(context->shout)); goto error; } } else { memset(mp3buf, 0, 128); ret = shout_send(context->shout, mp3buf, 128); } shout_sync(context->shout); switch_yield(100000); } error: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write Thread Done\n"); switch_thread_rwlock_unlock(context->rwlock); context->thread_running = 0; return NULL; }
void do_telecast(switch_stream_handle_t *stream) { char *path_info = switch_event_get_header(stream->param_event, "http-path-info"); char *uuid = strdup(path_info + 4); switch_core_session_t *tsession; char *fname = "stream.mp3"; if ((fname = strchr(uuid, '/'))) { *fname++ = '\0'; } if (!(tsession = switch_core_session_locate(uuid))) { char *ref = switch_event_get_header(stream->param_event, "http-referer"); stream->write_function(stream, "Content-type: text/html\r\n\r\n<h2>Not Found!</h2>\n" "<META http-equiv=\"refresh\" content=\"1;URL=%s\">", ref); } else { switch_media_bug_t *bug = NULL; switch_buffer_t *buffer = NULL; switch_mutex_t *mutex; switch_channel_t *channel = switch_core_session_get_channel(tsession); lame_global_flags *gfp = NULL; switch_codec_implementation_t read_impl = { 0 }; switch_core_session_get_read_impl(tsession, &read_impl); if (switch_channel_test_flag(channel, CF_PROXY_MODE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Stepping into media path so this will work!\n"); switch_ivr_media(uuid, SMF_REBRIDGE); } if (!(gfp = lame_init())) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate lame\n"); goto end; } lame_set_num_channels(gfp, read_impl.number_of_channels); lame_set_in_samplerate(gfp, read_impl.actual_samples_per_second); lame_set_brate(gfp, 16 * (read_impl.actual_samples_per_second / 8000) * read_impl.number_of_channels); lame_set_mode(gfp, 3); lame_set_quality(gfp, 2); lame_set_errorf(gfp, log_error); lame_set_debugf(gfp, log_debug); lame_set_msgf(gfp, log_msg); lame_set_bWriteVbrTag(gfp, 0); lame_mp3_tags_fid(gfp, NULL); lame_init_params(gfp); lame_print_config(gfp); switch_mutex_init(&mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(tsession)); switch_buffer_create_dynamic(&buffer, 1024, 2048, 0); switch_buffer_add_mutex(buffer, mutex); if (switch_core_media_bug_add(tsession, "telecast", NULL, telecast_callback, buffer, 0, SMBF_READ_STREAM | SMBF_WRITE_STREAM | SMBF_READ_PING, &bug) != SWITCH_STATUS_SUCCESS) { goto end; } stream->write_function(stream, "Content-type: audio/mpeg\r\n" "Content-Disposition: inline; filename=\"%s\"\r\n\r\n", fname); while (switch_channel_ready(channel)) { unsigned char mp3buf[TC_BUFFER_SIZE] = ""; int rlen; uint8_t buf[1024]; switch_size_t bytes = 0; if (switch_buffer_inuse(buffer) >= 1024) { switch_buffer_lock(buffer); bytes = switch_buffer_read(buffer, buf, sizeof(buf)); switch_buffer_unlock(buffer); } else { if (!bytes) { switch_cond_next(); continue; } memset(buf, 0, bytes); } if ((rlen = lame_encode_buffer(gfp, (void *) buf, NULL, bytes / 2, mp3buf, sizeof(mp3buf))) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MP3 encode error %d!\n", rlen); goto end; } if (rlen) { if (stream->raw_write_function(stream, mp3buf, rlen)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Disconnected\n"); goto end; } } } end: switch_safe_free(uuid); if (gfp) { lame_close(gfp); gfp = NULL; } if (bug) { switch_core_media_bug_remove(tsession, &bug); } if (buffer) { switch_buffer_destroy(&buffer); } switch_core_session_rwunlock(tsession); } }
void do_broadcast(switch_stream_handle_t *stream) { char *path_info = switch_event_get_header(stream->param_event, "http-path-info"); char *file; lame_global_flags *gfp = NULL; switch_file_handle_t fh = { 0 }; unsigned char mp3buf[TC_BUFFER_SIZE] = ""; uint8_t buf[1024]; int rlen; int is_local = 0; uint32_t interval = 20000; if (strstr(path_info + 7, "://")) { file = strdup(path_info + 7); is_local++; } else { file = switch_mprintf("%s/streamfiles/%s", SWITCH_GLOBAL_dirs.base_dir, path_info + 7); } assert(file); if (switch_core_file_open(&fh, file, 0, 0, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { memset(&fh, 0, sizeof(fh)); stream->write_function(stream, "Content-type: text/html\r\n\r\n<h2>File not found</h2>\n"); goto end; } if (switch_test_flag((&fh), SWITCH_FILE_NATIVE)) { stream->write_function(stream, "Content-type: text/html\r\n\r\n<h2>File format not supported</h2>\n"); goto end; } if (!(gfp = lame_init())) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate lame\n"); goto end; } lame_set_num_channels(gfp, fh.channels); lame_set_in_samplerate(gfp, fh.samplerate); lame_set_brate(gfp, 16 * (fh.samplerate / 8000) * fh.channels); lame_set_mode(gfp, 3); lame_set_quality(gfp, 2); lame_set_errorf(gfp, log_error); lame_set_debugf(gfp, log_debug); lame_set_msgf(gfp, log_msg); lame_set_bWriteVbrTag(gfp, 0); lame_mp3_tags_fid(gfp, NULL); lame_init_params(gfp); lame_print_config(gfp); stream->write_function(stream, "Content-type: audio/mpeg\r\n" "Content-Disposition: inline; filename=\"%s.mp3\"\r\n\r\n", path_info + 7); if (fh.interval) { interval = fh.interval * 1000; } for (;;) { switch_size_t samples = sizeof(buf) / 2; switch_core_file_read(&fh, buf, &samples); if (is_local) { switch_yield(interval); } if (!samples) { break; } if ((rlen = lame_encode_buffer(gfp, (void *) buf, NULL, samples, mp3buf, sizeof(mp3buf))) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MP3 encode error %d!\n", rlen); goto end; } if (rlen) { if (stream->raw_write_function(stream, mp3buf, rlen)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Disconnected\n"); goto end; } } } while ((rlen = lame_encode_flush(gfp, mp3buf, sizeof(mp3buf))) > 0) { if (stream->raw_write_function(stream, mp3buf, rlen)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Disconnected\n"); goto end; } } end: if (fh.channels) { switch_core_file_close(&fh); } switch_safe_free(file); if (gfp) { lame_close(gfp); gfp = NULL; } }
void *encode(void *init) { char file[256]; int fd1 = -1, fd2 = -1, fd_out = -1; uint32_t i, k; int16_t *b0 = 0, *b1 = 0, *b2 = 0; rec_ctx *ctx = (rec_ctx *) init; #ifdef USING_LAME lame_global_flags *gfp; #endif log_info("in encode thread"); pthread_join(ctx->rec1,0); pthread_join(ctx->rec2,0); log_info("recorder threads complete, encoding"); sprintf(file, OUT_DIR "/%s-up",ctx->cur_file); fd1 = open(file,O_RDONLY); sprintf(file, OUT_DIR "/%s-dn",ctx->cur_file); fd2 = open(file,O_RDONLY); if(fd1 < 0 || fd2 < 0) { if(fd1 >= 0) { close(fd1); sprintf(file, OUT_DIR "/%s-up",ctx->cur_file); unlink(file); } if(fd2 >= 0) { close(fd2); sprintf(file, OUT_DIR "/%s-dn",ctx->cur_file); unlink(file); } log_err("encode: input file not found"); return 0; } #ifdef USING_LAME if(ctx->ismp3) sprintf(file, OUT_DIR "/%s.mp3",ctx->cur_file); else #endif sprintf(file, OUT_DIR "/%s.wav",ctx->cur_file); fd_out = open(file,O_CREAT|O_TRUNC|O_WRONLY); if(fd_out < 0) { log_err("encode: cannot open output file %s",file); close(fd1); sprintf(file, OUT_DIR "/%s-up",ctx->cur_file); unlink(file); close(fd2); sprintf(file, OUT_DIR "/%s-dn",ctx->cur_file); unlink(file); return 0; } i = (uint32_t) lseek(fd1,0,SEEK_END); k = (uint32_t) lseek(fd2,0,SEEK_END); lseek(fd1,0,SEEK_SET); lseek(fd2,0,SEEK_SET); if(i != k) { log_info("file sizes mismatch"); if(i > k) i = k; } i &= ~1; if(i == 0) { log_err("zero size input file"); close(fd_out); unlink(file); close(fd1); sprintf(file, OUT_DIR "/%s-up",ctx->cur_file); unlink(file); close(fd2); sprintf(file, OUT_DIR "/%s-dn",ctx->cur_file); unlink(file); return 0; } #ifdef USING_LAME if(ctx->ismp3) { gfp = lame_init(); lame_set_errorf(gfp,lame_error_handler); lame_set_debugf(gfp,lame_error_handler); lame_set_msgf(gfp,lame_error_handler); lame_set_num_channels(gfp,2); lame_set_in_samplerate(gfp,8000); lame_set_brate(gfp,64); /* compress 1:4 */ lame_set_mode(gfp,0); /* mode = stereo */ lame_set_quality(gfp,2); /* 2=high 5 = medium 7=low */ if(lame_init_params(gfp) < 0) { log_err("encode: failed to init lame"); close(fd_out); unlink(file); close(fd1); sprintf(file, OUT_DIR "/%s-up",ctx->cur_file); unlink(file); close(fd2); sprintf(file, OUT_DIR "/%s-dn",ctx->cur_file); unlink(file); return 0; } #define CHSZ (512*1024) #define OCHSZ (5*(CHSZ/8)+7200) b0 = (int16_t *) malloc(OCHSZ); b1 = (int16_t *) malloc(CHSZ); b2 = (int16_t *) malloc(CHSZ); if(!b0 || !b1 || !b2) { log_err("encode: out of memory"); if(b0) free(b0); if(b1) free(b1); if(b2) free(b2); close(fd_out); unlink(file); close(fd1); sprintf(file, OUT_DIR "/%s-up",ctx->cur_file); unlink(file); close(fd2); sprintf(file, OUT_DIR "/%s-dn",ctx->cur_file); unlink(file); return 0; } k = 0; do { int ret = 0; uint32_t j = 0, count = 0; unsigned char *c1,*c2; for(c1 = (unsigned char*) b1, c2 = (unsigned char*) b2; count < CHSZ; c1 += ret, c2 += ret) { j = (k + RSZ > i) ? i - k : RSZ; ret = read(fd1,c1,j); if(ret < 0) break; ret = read(fd2,c2,j); if(ret < 0) break; k += ret; count += ret; if(k == i) break; } if(ret < 0) break; if(count) { ret = lame_encode_buffer(gfp,b1,b2,count/2,(unsigned char *)b0,OCHSZ); if(ret < 0) break; c1 = (unsigned char *) b0; count = ret; for(j = 0; j < count; j += RSZ, c1 += ret) { ret = (j + RSZ > count) ? count - j : RSZ; write(fd_out,c1,ret); } } } while(k < i); i = (uint32_t) lame_encode_flush(gfp,(unsigned char *)b0,OCHSZ); if(i) write(fd_out,b0,i); lame_close(gfp); } else { #endif b0 = (int16_t *) malloc(RSZ*2); b1 = (int16_t *) malloc(RSZ); b2 = (int16_t *) malloc(RSZ); if(!b0 || !b1 || !b2) { log_err("encode: out of memory"); if(b0) free(b0); if(b1) free(b1); if(b2) free(b2); close(fd_out); unlink(file); close(fd1); sprintf(file, OUT_DIR "/%s-up",ctx->cur_file); unlink(file); close(fd2); sprintf(file, OUT_DIR "/%s-dn",ctx->cur_file); unlink(file); return 0; } wavhdr.data_sz = i*2; wavhdr.riff_sz = i*2 + 36; write(fd_out,&wavhdr,sizeof(wavhdr)); k = 0; while(1) { uint32_t j, count = (k + RSZ > i) ? i - k : RSZ; if(read(fd1,b1,count) < 0) break; if(read(fd2,b2,count) < 0) break; for(j = 0; j < count/2; j++) { b0[2*j] = b1[j]; b0[2*j+1] = b2[j]; } write(fd_out,b0,count*2); k += count; if(k == i) break; } #ifdef USING_LAME } #endif close(fd1); close(fd2); close(fd_out); free(b0); free(b1); free(b2); log_info("encoding complete"); sprintf(file, OUT_DIR "/%s-up",ctx->cur_file); unlink(file); sprintf(file, OUT_DIR "/%s-dn",ctx->cur_file); unlink(file); free(ctx->x); free(ctx); return 0; }
int lame_encode_buffer_interleaved(lame_global_flags *gfp, short int buffer[], int nsamples, char *mp3buf, int mp3buf_size) { static int frame_buffered=0; int mp3size=0,ret,i,ch,mf_needed; /* some sanity checks */ assert(ENCDELAY>=MDCTDELAY); assert(BLKSIZE-FFTOFFSET >= 0); mf_needed = BLKSIZE+gfp->framesize-FFTOFFSET; assert(MFSIZE>=mf_needed); if (gfp->num_channels == 1) { return lame_encode_buffer(gfp,buffer, NULL ,nsamples,mp3buf,mp3buf_size); } if (gfp->resample_ratio!=1) { short int *buffer_l; short int *buffer_r; buffer_l=malloc(sizeof(short int)*nsamples); buffer_r=malloc(sizeof(short int)*nsamples); if (buffer_l == NULL || buffer_r == NULL) { return -1; } for (i=0; i<nsamples; i++) { buffer_l[i]=buffer[2*i]; buffer_r[i]=buffer[2*i+1]; } ret = lame_encode_buffer(gfp,buffer_l,buffer_r,nsamples,mp3buf,mp3buf_size); free(buffer_l); free(buffer_r); return ret; } if (gfp->frameNum==0 && !frame_buffered) { memset((char *) mfbuf, 0, sizeof(mfbuf)); frame_buffered=1; mf_samples_to_encode = ENCDELAY+288; mf_size=ENCDELAY-MDCTDELAY; /* we pad input with this many 0's */ } if (gfp->frameNum==1) { /* reset, for the next time frameNum==0 */ frame_buffered=0; } if (gfp->num_channels==2 && gfp->stereo==1) { /* downsample to mono */ for (i=0; i<nsamples; ++i) { buffer[2*i]=((int)buffer[2*i]+(int)buffer[2*i+1])/2; buffer[2*i+1]=0; } } while (nsamples > 0) { int n_out; /* copy in new samples */ n_out = Min(gfp->framesize,nsamples); for (i=0; i<n_out; ++i) { mfbuf[0][mf_size+i]=buffer[2*i]; mfbuf[1][mf_size+i]=buffer[2*i+1]; } buffer += 2*n_out; nsamples -= n_out; mf_size += n_out; assert(mf_size<=MFSIZE); mf_samples_to_encode += n_out; if (mf_size >= mf_needed) { /* encode the frame */ ret = lame_encode_frame(gfp,mfbuf[0],mfbuf[1],mf_size,mp3buf,mp3buf_size); if (ret == -1) { /* fatel error: mp3buffer was too small */ return -1; } mp3buf += ret; mp3size += ret; /* shift out old samples */ mf_size -= gfp->framesize; mf_samples_to_encode -= gfp->framesize; for (ch=0; ch<gfp->stereo; ch++) for (i=0; i<mf_size; i++) mfbuf[ch][i]=mfbuf[ch][i+gfp->framesize]; } } assert(nsamples==0); return mp3size; }
int CEncoderLame::encode(const sp<IMediaSource>& pMediaSource_in, const sp<IAudioSink>& pAudioSink_out) { AUTO_LOG(); CHECK_PTR_EXT(m_pGobalFlags, BAD_VALUE); CHECK_PTR_EXT(pMediaSource_in, BAD_VALUE); CHECK_PTR_EXT(pAudioSink_out, BAD_VALUE); sp<MetaData> pMeta = pMediaSource_in->getFormat(); CHECK_PTR_EXT(pMeta, BAD_VALUE); int32_t iChannelNum = 0; bool chk = pMeta->findInt32(kKeyChannelCount, &iChannelNum); CHECK_IS_EXT((true == chk), UNKNOWN_ERROR); int ret = lame_set_num_channels(m_pGobalFlags, iChannelNum); CHECK_IS_EXT((ret == OK), ret); // only support one channel and two channels CHECK_IS_EXT(((1 == iChannelNum) || (2 == iChannelNum)), INVALID_OPERATION); ret = pMediaSource_in->start(); CHECK_IS_EXT((ret == OK), ret); MediaBuffer* pBuf = NULL; while (OK == (pMediaSource_in->read(&pBuf, NULL))) { if (pBuf == NULL) { break; } if ((pBuf->data() == NULL) || (pBuf->range_length() == 0)) { pBuf->release(); pBuf = NULL; continue; } int16_t *pOrg = (int16_t *)((const char *)pBuf->data() + pBuf->range_offset()); ssize_t iSamplesRead = pBuf->range_length() / 2; pOrg += iSamplesRead; iSamplesRead /= iChannelNum; CHECK_NE(iSamplesRead, 0); int iMP3BufSize = 1.25 * iSamplesRead + 7200; short int* pPCMBufL = new short int[iSamplesRead]; short int* pPCMBufR = new short int[iSamplesRead]; unsigned char* pMP3Buf = new unsigned char[iMP3BufSize]; if (iChannelNum == 2) { for (ssize_t i = iSamplesRead; --i >= 0;) { pPCMBufR[i] = *--pOrg; pPCMBufL[i] = *--pOrg; } } else if (iChannelNum == 1) { memset(pPCMBufR, 0, iSamplesRead * sizeof(short int)); for (ssize_t i = iSamplesRead; --i >= 0;) { pPCMBufL[i] = *--pOrg; } } else { // EMPTY } int iOutSize = lame_encode_buffer(m_pGobalFlags, pPCMBufL, pPCMBufR, iSamplesRead, pMP3Buf, iMP3BufSize); int iWriteSize = iOutSize; if (iOutSize > 0) { iWriteSize = pAudioSink_out->write(pMP3Buf, iOutSize); } delete (pMP3Buf); delete (pPCMBufR); delete (pPCMBufL); pBuf->release(); pBuf = NULL; CHECK_IS_EXT((iOutSize == iWriteSize), UNKNOWN_ERROR); } // last frame may remain { unsigned char* pMP3Buf = new unsigned char[LAME_MAXMP3BUFFER]; int iOutSize = lame_encode_flush(m_pGobalFlags, pMP3Buf, sizeof(pMP3Buf)); int iWriteSize = iOutSize; if (iOutSize > 0) { iWriteSize = pAudioSink_out->write(pMP3Buf, iOutSize); } delete (pMP3Buf); CHECK_IS_EXT((iOutSize == iWriteSize), UNKNOWN_ERROR); } // write the tag3v1 { unsigned char* pMP3Buf = new unsigned char[128]; int iOutSize = lame_get_id3v1_tag(m_pGobalFlags, pMP3Buf, sizeof(pMP3Buf)); int iWriteSize = iOutSize; if ((iOutSize > 0) && (((size_t)iOutSize) <= sizeof(pMP3Buf))) { iWriteSize = pAudioSink_out->write(pMP3Buf, iOutSize); } delete (pMP3Buf); CHECK_IS_EXT((iOutSize == iWriteSize), UNKNOWN_ERROR); } RETURN(OK); }
bool Mp3Writer::write(QByteArray &left, QByteArray &right, long samples, bool flush) { int ret; QByteArray output; // rough upper bound formula taken from lame.h long size = samples + samples / 4 + 7200; do { output.resize(size); if (stereo) { ret = lame_encode_buffer(lame, reinterpret_cast<const short *>(left.constData()), reinterpret_cast<const short *>(right.constData()), samples, reinterpret_cast<unsigned char *>(output.data()), output.size()); } else { // lame.h claims to write to the buffers, even though they're declared const, be safe // TODO: this mixes both channels again! can lame take only mono samples? ret = lame_encode_buffer(lame, reinterpret_cast<const short *>(left.data()), reinterpret_cast<const short *>(left.data()), samples, reinterpret_cast<unsigned char *>(output.data()), output.size()); } if (ret == -1) { // there wasn't enough space in output size *= 2; continue; } } while (false); if (ret < 0) { debug(QString("Error while writing MP3 file, code = %1").arg(ret)); return false; } samplesWritten += samples; if (ret > 0) { output.truncate(ret); file.write(output); } left.remove(0, samples * 2); if (stereo) right.remove(0, samples * 2); if (!flush) return true; // flush mp3 output.resize(10240); ret = lame_encode_flush(lame, reinterpret_cast<unsigned char *>(output.data()), output.size()); lame_close(lame); lame = NULL; hasFlushed = true; if (ret < 0) { debug(QString("Error while flushing MP3 file, code = %1").arg(ret)); return false; } if (ret > 0) { output.truncate(ret); file.write(output); } return true; }
int main(int argc, char **argv) { char mp3buffer[LAME_MAXMP3BUFFER]; short int Buffer[2][1152]; int iread,imp3; lame_global_flags gf; FILE *outf; #ifdef __riscos__ int i; #endif lame_init(&gf); /* initialize libmp3lame */ if(argc==1) lame_usage(&gf,argv[0]); /* no command-line args, print usage, exit */ /* parse the command line arguments, setting various flags in the * struct 'gf'. If you want to parse your own arguments, * or call libmp3lame from a program which uses a GUI to set arguments, * skip this call and set the values of interest in the gf struct. * (see lame.h for documentation about these parameters) */ lame_parse_args(&gf,argc, argv); if (!gf.gtkflag) { /* open the MP3 output file */ if (!strcmp(gf.outPath, "-")) { #ifdef __EMX__ _fsetmode(stdout,"b"); #elif (defined __BORLANDC__) setmode(_fileno(stdout), O_BINARY); #elif (defined __CYGWIN__) setmode(fileno(stdout), _O_BINARY); #elif (defined _WIN32) _setmode(_fileno(stdout), _O_BINARY); #endif outf = stdout; } else { if ((outf = fopen(gf.outPath, "wb")) == NULL) { fprintf(stderr,"Could not create \"%s\".\n", gf.outPath); exit(1); } } #ifdef __riscos__ /* Assign correct file type */ for (i = 0; gf.outPath[i]; i++) if (gf.outPath[i] == '.') gf.outPath[i] = '/'; SetFiletype(gf.outPath, 0x1ad); #endif } /* open the wav/aiff/raw pcm or mp3 input file. This call will * open the file with name gf.inFile, try to parse the headers and * set gf.samplerate, gf.num_channels, gf.num_samples. * if you want to do your own file input, skip this call and set * these values yourself. */ lame_init_infile(&gf); /* Now that all the options are set, lame needs to analyze them and * set some more options */ lame_init_params(&gf); lame_print_config(&gf); /* print usefull information about options being used */ #ifdef HAVEGTK if (gf.gtkflag) gtk_init (&argc, &argv); if (gf.gtkflag) gtkcontrol(&gf); else #endif { /* encode until we hit eof */ do { /* read in 'iread' samples */ iread=lame_readframe(&gf,Buffer); /* encode */ imp3=lame_encode_buffer(&gf,Buffer[0],Buffer[1],iread, mp3buffer,(int)sizeof(mp3buffer)); /* was our output buffer big enough? */ if (imp3==-1) { fprintf(stderr,"mp3 buffer is not big enough... \n"); exit(1); } if (fwrite(mp3buffer,1,imp3,outf) != imp3) { fprintf(stderr,"Error writing mp3 output"); exit(1); } } while (iread); } imp3=lame_encode_finish(&gf,mp3buffer,(int)sizeof(mp3buffer)); /* may return one more mp3 frame */ fwrite(mp3buffer,1,imp3,outf); fclose(outf); lame_close_infile(&gf); /* close the input file */ lame_mp3_tags(&gf); /* add id3 or VBR tags to mp3 file */ return 0; }