Question

I was trying to conver audio formats to ogg ( vorbis ) file using Xuggler.

First, i've attemted the very basic way to do it,

IMediaReader readermp3 = ToolFactory.makeReader(sourcefile);
IMediaWriter writer = ToolFactory.makeWriter(targetfilemp3, readermp3);
readermp3.addListener(writer);
while (readermp3.readPacket() == null)

targetfile ended with .ogg. This actually works, however it encodes to ogg FLAC instead of ogg vorbis.

Then i've tried to do some of its parts manually,

First - Get the original sample rate and channel number, Second - addaudiostream using these sample rate,channel number AND Codec id for vorbis.

IMediaReader readermp3 = ToolFactory.makeReader(sourcefile);
    IContainer readercontainer = readermp3.getContainer();
    readercontainer.open(sourcefile, IContainer.Type.READ,null);

    int numStreams = readercontainer.getNumStreams();  

    IStream stream = null;
    for(int i = 0; i < numStreams; i++) {  
    stream = readercontainer.getStream(i); } 

IStreamCoder mycoder = stream.getStreamCoder();
int sourcechannels,sourcesamplerate;
sourcechannels = mycoder.getChannels();
sourcesamplerate = mycoder.getSampleRate();

/* these were for getting samplerate and channels i don't think they are relevant but im */copying it here just incase

IMediaWriter writer = ToolFactory.makeWriter(targetfilemp3, readermp3);
writer.addAudioStream(0, 0,ICodec.ID.CODEC_ID_VORBIS,sourcechannels, sourcesamplerate);
readermp3.addListener(writer);
while (readermp3.readPacket() == null)
       ;

When i try to run this, it gives me an error "ERROR org.ffmpeg - [libvorbis @ 0436F300] Specified sample_fmt is not supported." "WARN com.xuggle.xuggler - Error: could not open codec (../../../../../../../csrc/com/xuggle/xuggler/StreamCoder.cpp:831)"

Sidenote = it works with mp3,wav and flac ogg file. Also, i have tried changing my extension to .vorbis instead of .ogg. Still the same error.

Then ofcourse, i googled it. There is only 1 relevant q/a about this issue https://groups.google.com/forum/?fromgroups=#!topic/xuggler-users/18hsI_LGxI4

however, i didn't understand the answer =).

Thanks a lot for the answers.

Was it helpful?

Solution

There's a funky thing going on with Xuggler where it doesn't always allow you to set the sample rate of IAudioSamples. You'll need to use an IAudioResampler.

Took me a while to figure this out. This post by Marty helped a lot, though his code is outdated now.

Here's how you fix it.

.

Before encoding

I'm assuming here that audio input has been properly set up, resulting in an IStreamCoder called audioCoder.

After that's done, you are probably initiating an IMediaWriter and adding an audio stream like so:

final IMediaWriter oggWriter = ToolFactory.makeWriter(oggOutputFile);

// Using stream 1 'cause there is also a video stream.
// For an audio only file you should use stream 0.
oggWriter.addAudioStream(1, 1, ICodec.ID.CODEC_ID_VORBIS, 
                         audioCoder.getChannels(), audioCoder.getSampleRate());

Now create an IAudioResampler:

IAudioResampler oggResampler = IAudioResampler.make(audioCoder.getChannels(), 
                                                   audioCoder.getChannels(), 
                                                   audioCoder.getSampleRate(),
                                                   audioCoder.getSampleRate(),  
                                                   IAudioSamples.Format.FMT_FLT, 
                                                   audioCoder.getSampleFormat());

And tell your IMediaWriter to update to its sample format:

// The stream 1 here is consistent with the stream we added earlier.
oggWriter.getContainer().getStream(1).getStreamCoder().
                         setSampleFormat(IAudioSamples.Format.FMT_FLT);

.

During encoding

You are currently probably initiating an IAudioSamples and filling it with audio data, like so:

IAudioSamples audioSample = IAudioSamples.make(512, audioCoder.getChannels(), 
                                                    audioCoder.getSampleFormat());

int bytesDecoded = audioCoder.decodeAudio(audioSample, packet, offset);

Now initiate an IAudioSamples for our resampled data:

IAudioSamples vorbisSample = IAudioSamples.make(512, audioCoder.getChannels(),
                                                IAudioSamples.Format.FMT_FLT);

Finally, resample the audio data and write the result:

oggResampler.resample(vorbisSample, audioSample, 0);

oggWriter.encodeAudio(1, vorbisSample);  

.

Final thought

Just a hint to get your output files to play well:

  • If you use audio and video within the same container, then audio and video data packets should be written in such an order that the timestamp of each data packet is higher than that of the previous data packet. So you are almost certainly going to need some kind of buffering mechanism that alternates writing audio and video.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top