Resample it yourself
Did you guys ever try to resample audio-data of a clip in java? The JMF not very helpful, but today I will give you a little introduction to the xuggle library which will do that for you.
Xuggler is a library with the power of ffmpeg in your java application. A couple of weeks ago it was able to play video clips in your java application. But the real awesome stuff came with the new version of Xuggler. In version 3.0, which was released under AGPL
, the MediaTools showed up. Now its possible to decode and encode your video clip from any format to any format.
If that is everything you need, you’ll be fine with just that. But if you need to resample the audio data (what you need, if you want to put the clip into, lets say, a FLV-Container), you need to implement a little more then just
while(packet.read() == null);
First step is to create your own writer. It will extend the MediaToolAdapter so we just need to override the methods we need and then give the result to the adapter.
public class ConfigureListener extends MediaToolAdapter
I called it “ConfigureListener” because its listening to the reader and then configuring it. But you can name it what ever you want.
Second step is to override the onAddStream-method which is called, when the reader gets a new stream and adds it to the listeners. If this method is called, we know there is a new stream, so we can check, what stream there is. if it is a audiostream, we can start to create a resampler.
@Override
public void onAddStream(IAddStreamEvent event) {
int streamIndex = event.getStreamIndex();
IStreamCoder streamCoder = event.getSource().getContainer()
.getStream(streamIndex).getStreamCoder();
if (streamCoder.getCodecType() == ICodec.Type.CODEC_TYPE_AUDIO) {
streamCoder.setSampleRate(44100);
}
}
If its not a audiostream, we just ignore it. After we set up the new sample rate for the stream, we got to give the event up to the parent-class, the MediaToolAdapter, so the event will got handled correctly.
super.onAddStream(event);
if that is done, the container, and the stream, knows that the output will be in in 44100 Hz, what you need to use to create FLV-Container.
But were not quite done. We need to resample every audiopacket. So we need to override the method onAudioSamples as well. This method get called for every audiopacket which is processed by the reader. So we create a IAudioResampler with the global instance of IAudioResampler and call its make-method. That will create us a IAudioResampler-object which will resample our audiosamples.
if (resampler == null) {
resampler = IAudioResampler.make(
2, // output channels
samples.getChannels(), // input channels
44100, // new sample rate
samples.getSampleRate() // old sample rate
);
}
We are doing that only once, because its take some time and the sample rate doesnt change in a clip.
If we got our resampler we will use it to resample the audiodata given by the event attribute:
if (resampler != null && event.getAudioSamples().getNumSamples() > 0) {
IAudioSamples out = IAudioSamples.make(
samples.getNumSamples(), samples.getChannels());
resampler.resample(out, samples, samples.getNumSamples());
AudioSamplesEvent ase = new AudioSamplesEvent(
event.getSource(), out, event.getStreamIndex());
super.onAudioSamples(ase);
out.delete();
}
First we are creating an output object, which will hold our resampled data. Then we can finally call our resampler to resample the audio data. After that, we need to put the resampled data into a new AudioSamplesEvent, so we can give this event, with our new (resampled) audio data, to the parent-class with:
super.onAudioSamples(ase);
So it will be handled by the MediaToolAdapter and be put into your container with the correct (or even a different) audio sample rate.
Find the the complete source code here (ConfigureListeer.java)
You just need to put it into your project and implement it in the reader-writer-chain like this:
IMediaReader reader = ToolFactory.makeReader(filename); ConfigureListener cl = new ConfigureListener(); reader.addListener(cl); IMediaWriter writer = ToolFactory.makeWriter(outname, reader); cl.addListener(writer);
And read/write the stuff:
while (reader.readPacket() == null);
thanks for reader,
Martin
1 Comment
Other Links to this Post
RSS feed for comments on this post. TrackBack URI
Leave a comment
You must be logged in to post a comment.