summaryrefslogtreecommitdiff
path: root/server/liblame_wrapper.cc
diff options
context:
space:
mode:
Diffstat (limited to 'server/liblame_wrapper.cc')
-rw-r--r--server/liblame_wrapper.cc293
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;
+}