diff options
Diffstat (limited to 'server/liblame_wrapper.cc')
-rw-r--r-- | server/liblame_wrapper.cc | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/server/liblame_wrapper.cc b/server/liblame_wrapper.cc new file mode 100644 index 0000000..5603d6f --- /dev/null +++ b/server/liblame_wrapper.cc @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * liblame_wrapper.cc + * + * Sat Jul 2 11:11:34 CEST 2005 + * Copyright 2005 Bent Bisballe + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of MIaV. + * + * MIaV 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. + * + * MIaV 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 MIaV; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include <config.h> +#include "liblame_wrapper.h" +#include "miav_config.h" + +LibLAMEWrapper::LibLAMEWrapper(Info *i) +{ + info = i; + + // Init library. + if( (gfp = lame_init()) == NULL) { + info->error("LAME initialization failed (due to malloc failure!)"); + return; + } + + lame_set_in_samplerate(gfp, INPUT_SAMPLE_RATE); + lame_set_out_samplerate(gfp, OUTPUT_SAMPLE_RATE); + + lame_set_num_channels(gfp, CHANNELS); + // lame_set_num_samples(gfp, 1152); + // lame_set_num_samples(gfp, SAMPLES); + // lame_set_num_samples(gfp, 0); + + lame_set_quality(gfp, config->readInt("mp3_quality")); + lame_set_mode(gfp, STEREO); + lame_set_brate(gfp, config->readInt("mp3_bitrate")); + + lame_set_strict_ISO(gfp, 1); + + // 1 = write a Xing VBR header frame. + lame_set_bWriteVbrTag(gfp, 0); + + // Types of VBR. default = vbr_off = CBR + // lame_set_VBR(gfp, vbr_rh); + + // VBR quality level. 0=highest 9=lowest + // lame_set_VBR_q(gfp, 6); + + lame_set_copyright(gfp, 0); // is there a copyright on the encoded data? + lame_set_original(gfp, 1); // is the encoded data on the original media? + lame_set_error_protection(gfp, 0);// add 2 byte CRC protection to each frame? + lame_set_padding_type(gfp, PAD_NO); // PAD_NO, PAD_ALL, PAD_ADJUST, PAD_MAX_INDICATOR + // 0 = do not pad frames + // 1 = always pad frames + // 2 = adjust padding to satisfy bit rate + lame_set_extension(gfp, 0); // private extension bit + + + if (lame_init_params(gfp) < 0) { + info->error("LAME parameter initialization failed."); + return; + } + + audio_buffer[0] = new int16_t[AUDIO_BUFFER_SIZE]; + audio_buffer[1] = new int16_t[AUDIO_BUFFER_SIZE]; + + // And now for the dv decoder! + decoder = NULL; + + calc_bitrate = 0; + frame_number = 0; +} + +LibLAMEWrapper::~LibLAMEWrapper() +{ + delete audio_buffer[0]; + delete audio_buffer[1]; +} + +Frame *LibLAMEWrapper::close(Frame *oldframe) +{ + Frame *frame; + unsigned int offset = 0; + + frame = new Frame(NULL, (int)(1.25 * SAMPLES + 7200) * 2); // Big enough to hold two frames + + if(oldframe) { + offset = oldframe->size; + frame->number = oldframe->number; + memcpy(frame->data, oldframe->data, oldframe->size); + delete oldframe; + } + + int flush; + + flush = lame_encode_finish(gfp, frame->data + offset, 7200); + + frame->size = offset + flush; + + calc_bitrate += flush; + frame->bitrate = (unsigned int)((double)calc_bitrate / (double)(frame_number)) * 25; + + return frame; +} + +#include <math.h> +static unsigned int sin_cnt = 0; +Frame *LibLAMEWrapper::encode(Frame *dvframe) +{ + if(dvframe->mute) { + // Overwrite audiobuffer with dummy data + double volume = 1000; // Min:= 0 - Max := 32000 + double frequency = 440; // in Hz + + for(int cnt = 0; cnt < SAMPLES; cnt++) { + sin_cnt++; + double sin_val = (((double)sin_cnt / (double)OUTPUT_SAMPLE_RATE) * (double)M_PI) * frequency; + audio_buffer[0][cnt] = audio_buffer[1][cnt] = (short int)(sin(sin_val) * volume); + } + + // memset(audio_buffer[0], 0, sizeof(audio_buffer[0])); + // memset(audio_buffer[1], 0, sizeof(audio_buffer[1])); + } else { + // Decode audio from dv frame + if(!decoder) { + decoder = dv_decoder_new(FALSE/*this value is unused*/, FALSE, FALSE); + decoder->quality = DV_QUALITY_BEST; + + dv_parse_header(decoder, dvframe->data); + + decoder->system = e_dv_system_625_50; // PAL lines, PAL framerate + decoder->sampling = e_dv_sample_422; // 4 bytes y, 2 bytes u, 2 bytes v + decoder->std = e_dv_std_iec_61834; + decoder->num_dif_seqs = 12; + } + // Decode audio using libdv + dv_decode_full_audio( decoder, dvframe->data, audio_buffer ); + } + + /** + * input pcm data, output (maybe) mp3 frames. + * This routine handles all buffering, resampling and filtering for you. + * + * The required mp3buf_size can be computed from num_samples, + * samplerate and encoding rate, but here is a worst case estimate: + * + * return code number of bytes output in mp3buffer. can be 0 + * if return code = -1: mp3buffer was too small + * + * mp3buf_size in bytes = 1.25*num_samples + 7200 + * + * I think a tighter bound could be: (mt, March 2000) + * MPEG1: + * num_samples*(bitrate/8)/samplerate + 4*1152*(bitrate/8)/samplerate + 512 + * MPEG2: + * num_samples*(bitrate/8)/samplerate + 4*576*(bitrate/8)/samplerate + 256 + * + * but test first if you use that! + * + * set mp3buf_size = 0 and LAME will not check if mp3buf_size is + * large enough. + * + * NOTE: + * if gfp->num_channels=2, but gfp->mode = 3 (mono), the L & R channels + * will be averaged into the L channel before encoding only the L channel + * This will overwrite the data in buffer_l[] and buffer_r[]. + * + */ + Frame* audio_frame = new Frame(NULL, (int)(1.25 * SAMPLES + 7200)); + + const short int *buffer_l = audio_buffer[0]; // PCM data for left channel + const short int *buffer_r = audio_buffer[1]; // PCM data for right channel + const int nsamples = SAMPLES; // number of samples per channel + unsigned char* mp3buf = audio_frame->data; // pointer to encoded MP3 stream + const int mp3buf_size = audio_frame->size; // number of valid octets in this + + int val; + val = lame_encode_buffer(gfp, buffer_l, buffer_r, nsamples, mp3buf, mp3buf_size); + // val = lame_encode_mp3_frame(gfp, buffer_l, buffer_r, mp3buf, mp3buf_size); + + // info->info("Framenr: %d", lame_get_frameNum(gfp)); + + if(val < 0) { + switch(val) { + case -1: // mp3buf was too small + info->error("Lame encoding failed, mp3buf was too small."); + break; + case -2: // malloc() problem + info->error("Lame encoding failed, due to malloc() problem."); + break; + case -3: // lame_init_params() not called + info->error("Lame encoding failed, lame_init_params() not called."); + break; + case -4: // psycho acoustic problems + info->error("Lame encoding failed, due to psycho acoustic problems."); + break; + default: + info->error("Lame encoding failed, due to unknown error."); + break; + } + } + + /** + * OPTIONAL: + * lame_encode_flush_nogap will flush the internal mp3 buffers and pad + * the last frame with ancillary data so it is a complete mp3 frame. + * + * 'mp3buf' should be at least 7200 bytes long + * to hold all possible emitted data. + * + * After a call to this routine, the outputed mp3 data is complete, but + * you may continue to encode new PCM samples and write future mp3 data + * to a different file. The two mp3 files will play back with no gaps + * if they are concatenated together. + * + * This routine will NOT write id3v1 tags into the bitstream. + * + * return code = number of bytes output to mp3buf. Can be 0 + */ + + int flush_sz = 0; + + /* + flush_sz = lame_encode_flush_nogap(gfp, // global context handle + mp3buf + val, // pointer to encoded MP3 stream + mp3buf_size - val); // number of valid octets in this stream + */ + + // info->info("VAL: %d - FLUSH_SZ: %d - TOTAL: %d", val, flush_sz, (val + flush_sz)); + + audio_frame->size = val + flush_sz; + + /* + + int bitrate_kbps[14]; + // lame_bitrate_kbps(gfp, bitrate_kbps); + lame_bitrate_hist(gfp, bitrate_kbps); + // 32 40 48 56 64 80 96 112 128 160 192 224 256 320 + info->info("%d %d %d %d %d %d %d %d %d %d %d %d %d %d", + bitrate_kbps[0], + bitrate_kbps[1], + bitrate_kbps[2], + bitrate_kbps[3], + bitrate_kbps[4], + bitrate_kbps[5], + bitrate_kbps[6], + bitrate_kbps[7], + bitrate_kbps[8], + bitrate_kbps[9], + bitrate_kbps[10], + bitrate_kbps[11], + bitrate_kbps[12], + bitrate_kbps[13]); + */ + // while(frame_number != lame_get_frameNum(gfp)) { + + calc_bitrate += audio_frame->size;//lame_get_framesize(gfp); + frame_number ++;//= 1;//lame_get_frameNum(gfp); + + // info->info("lame_get_frameNum(gfp) %d ?= frame_number %d", lame_get_frameNum(gfp), frame_number); + // } + + // Bits pr. second + // 25 * 7 frames pr.second (it seems!) + audio_frame->bitrate = (unsigned int)((double)calc_bitrate / (double)(frame_number)) * 25; + /* + info->info("Audio size: %d, bitrate: %.4f", + audio_frame->bitrate, + (float)(config->readInt("mp3_bitrate") * 1000)/(float)(audio_frame->bitrate)); + */ + + /* + FILE* fp = fopen("/tmp/audiotest.mp3", "a"); + fwrite(audio_frame->data, audio_frame->size, 1, fp); + fclose(fp); + */ + return audio_frame; +} |