views:

187

answers:

1

Hello,

I'm using lame encoder to convert a wav to an mp3 in mac osx using objective-c and cocoa. I'm a complete novice when it comes to audio encoding and my C skills aren't great. Regardless I've stumbled along and gotten to the actual encoding stage, which is where i'm stuck.

From the code I've studied, it looks like I should be using lame_encode_buffer for mono and lame_encode_buffer_interleaved for stereo (although the fact that the former takes input for both the left and right channels confuses me). The code I've got so far is:

-(BOOL)encodeWave:(Wave *)wav {
    if(![self loadLibrary]) {
        return FALSE;
    }

    lame_set_num_channels(lgf,[wav channels]);
    lame_set_in_samplerate(lgf,[wav sampleRate]);
    lame_set_out_samplerate(lgf,[wav sampleRate]);
    lame_set_brate(lgf, [wav getBrateInK]);

    lame_init_params(lgf);

    //encode stuff!
    int total_samples = ([wav data_length] / [wav bytesPerSample]);
    int n_samples = total_samples / [wav channels];
    Byte * inBuf = (Byte *)malloc([wav data_length]);
    if(inBuf == NULL)
        return FALSE;
    memcpy(inBuf, [[wav data] bytes], [wav data_length]);
    int outBuf_size = 7200 + (1.25*n_samples);
    unsigned char * outBuf = (unsigned char *)malloc(outBuf_size);
    if(outBuf == NULL)
        return FALSE;
    lame_encode_buffer(lgf,(short int *)inBuf,(short int *)inBuf, n_samples, outBuf, outBuf_size);

    return TRUE;

}

-(BOOL)loadLibrary {

    NSString * pathToLib = [LAME_LIB_LIKELY_LOC stringByAppendingPathComponent:LAME_LIB_NAME];

    if(![[NSFileManager defaultManager] fileExistsAtPath:pathToLib])
        return FALSE;

    void * lib_handle = dlopen("libmp3lame.dylib",RTLD_LOCAL|RTLD_LAZY);
    if(!lib_handle)
        return FALSE;

    //Init
    lgf = lame_init();

    //set error processor
    lame_set_errorf(lgf,errorHandler);
    lame_set_debugf(lgf,errorHandler);
    lame_set_msgf(lgf,errorHandler);


    return TRUE;

}

I've used test code on inBuf to print out all the data and it looks right. When I have a break point on lame_encode_buffer all the parameters are assigned to their rightful values (i.e. no nil pointers).

I'm guessing this is more of me using the wrong method or giving the wrong type of input to the function, but with no good walkthroughs on this available, I really have no clue.

Edit (Backtrace)

#0  0x96e6ae42 in __kill ()
#1  0x96e6ae34 in kill$UNIX2003 ()
#2  0x96edd23a in raise ()
#3  0x96ee9679 in abort ()
#4  0x96ede3db in __assert_rtn ()
#5  0x000938ca in convert_partition2scalefac_l (gfc=0x146ca000, eb=0xbfff3c38, thr=0xbfff3d3c, chn=0) at psymodel.c:498
#6  0x00097c0b in L3psycho_anal_ns (gfp=0x877000, buffer=0xbfff8cac, gr_out=0, ms_ratio=0x146d6eb4, ms_ratio_next=0xbfffcb9c, masking_ratio=0xbfffd390, masking_MS_ratio=0xbfffcbf0, percep_entropy=0xbfffcbb0, percep_MS_entropy=0xbfffcba0, energy=0xbfffcbc8, blocktype_d=0xbfffac24) at psymodel.c:1712
#7  0x00086fa0 in lame_encode_mp3_frame (gfp=0x877000, inbuf_l=0x146ca010, inbuf_r=0x146cde50, mp3buf=0x877800 "", mp3buf_size=9537) at encoder.c:374
#8  0x0008a6e1 in lame_encode_frame (gfp=0x877000, inbuf_l=0x0, inbuf_r=0x0, mp3buf=0x0, mp3buf_size=0) at lame.c:1364
#9  0x0008ab57 in lame_encode_buffer_sample_t (gfp=0x877000, buffer_l=0x146f5000, buffer_r=0x160c0000, nsamples=0, mp3buf=0x877800 "", mp3buf_size=9537) at lame.c:1541
#10 0x0008ad6e in lame_encode_buffer (gfp=0x877000, buffer_l=0xbfffdcb0, buffer_r=0xbfffe5b0, nsamples=576, mp3buf=0x877800 "", mp3buf_size=9537) at lame.c:1591
#11 0x0008ca3f in lame_encode_flush (gfp=0x877000, mp3buffer=0x877000 "\377\377\377\377\001", mp3buffer_size=9537) at lame.c:1869
#12 0x00011d25 in -[MP3EncodingService encodeWave:] (self=0x1d96e0, _cmd=0x14c9f, wav=0x14712460) at /Users/tim/sp/MP3EncodingService.m:50
#13 0x0000edfb in -[LibraryController convert:] (self=0x1887f0, _cmd=0x15046, sender=0x198480) at /Users/tim/sp/LibraryController.m:908
#14 0x93a794cb in -[NSApplication sendAction:to:from:] ()
#15 0x93a79408 in -[NSControl sendAction:to:] ()
#16 0x93a7928e in -[NSCell _sendActionFrom:] ()
#17 0x93a788e7 in -[NSCell trackMouse:inRect:ofView:untilMouseUp:] ()
#18 0x93a7813a in -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] ()
#19 0x93a779f4 in -[NSControl mouseDown:] ()
#20 0x93a76133 in -[NSWindow sendEvent:] ()
#21 0x93a42cd9 in -[NSApplication sendEvent:] ()
#22 0x939a062f in -[NSApplication run] ()
#23 0x9396d834 in NSApplicationMain ()
#24 0x0000292c in main (argc=1, argv=0xbffff748) at /Users/tim/sp/main.m:13
+7  A: 

Hard to say. You're probably overrunning an array. As it seems that your output array has the right length, it's probably the input array. If you're lucky, simply try to give n_samples / 2 (because 2 == sizeof(short)) instead of n_samples as an argument to lame_encode_buffer.

The real, serious way to find a solution to your problem is:

  1. Recompile your lame library with debug info (-g option to the compiler) so that you get useful line information in your gdb backtrace.
  2. Then, get the gdb backtrace again, and see if you can tell where the segfault comes from.
  3. Run this under valgrind, which will tell you where the illegal access occurs (as the segfault might not occur on the first illegal access).

I'd bet it has something to do with the array length you pass, though :)

FX
Right, with n_samples / 2 it initially stopped the exception, but produced a garbage mp3 - It later stopped working once debug was enabled. I've updated the backtrace in the original post with debug data in - that suggests the problem occurs in lame_encode_flush. Running under valgrind suggests that the problems occur in lame_encode_buffer with a couple of invalid pointer sizes ("Invalid write of size 1") and several usages of undefined variables ("Conditional jump or move depends on uninitialised value(s)") before it dies.
Septih
So, it's not a segfault any more, it's an assertion failure: apparently, you get a negative sum of thresholds in convert_partition2scalefac_l, which is certainly not expected. Are you sure your input data is in the correct format?Another idea, in the absence of good walkthrough: look at lots of examples by searching for "lame_encode_buffer" in Google codesearch (www.google.com/codesearch)
FX
I've looked at quite a lot of the examples from codesearch (though 8/10 of the results are the library itself) and the repeating theme is that it's difficult to discern how they build their input data as usually these projects will convert many formats to mp3, not just wav. I'll keep looking through anyway, thank you for the debugging assistance.
Septih