Use Java to convert any media type to FLV with Xuggler (part 2)

Hello Folks,

After some debugging, we could find some problems with my code in the previous post. Fortunately, i could fix all the issues, and now i’m publishing the final class:


public class ConvertVideo extends MediaToolAdapter implements Runnable {
 private int VIDEO_WIDTH = 712;
 private int VIDEO_HEIGHT = 429;

 private IMediaWriter writer;
 private IMediaReader reader;
 private File outputFile;

 public ConvertVideo(File inputFile, File outputFile) {
 this.outputFile = outputFile;
 reader = ToolFactory.makeReader(inputFile.getAbsolutePath());
 reader.addListener(this);
}

 private IVideoResampler videoResampler = null;
 private IAudioResampler audioResampler = null;

 @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) {
 writer.addAudioStream(streamIndex, streamIndex, 2, 44100);
 } else if (streamCoder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) {
 streamCoder.setWidth(VIDEO_WIDTH);
 streamCoder.setHeight(VIDEO_HEIGHT);
 writer.addVideoStream(streamIndex, streamIndex, VIDEO_WIDTH, VIDEO_HEIGHT);
 }
 super.onAddStream(event);
 }

 @Override
 public void onVideoPicture(IVideoPictureEvent event) {
 IVideoPicture pic = event.getPicture();
 if (videoResampler == null) {
 videoResampler = IVideoResampler.make(VIDEO_WIDTH, VIDEO_HEIGHT, pic.getPixelType(), pic.getWidth(), pic.getHeight(), pic.getPixelType());
 }
 IVideoPicture out = IVideoPicture.make(pic.getPixelType(), VIDEO_WIDTH, VIDEO_HEIGHT);
 videoResampler.resample(out, pic);

 IVideoPictureEvent asc = new VideoPictureEvent(event.getSource(), out, event.getStreamIndex());
 super.onVideoPicture(asc);
 out.delete();
 }

 @Override
 public void onAudioSamples(IAudioSamplesEvent event) {
 IAudioSamples samples = event.getAudioSamples();
 if (audioResampler == null) {
 audioResampler = IAudioResampler.make(2, samples.getChannels(), 44100, samples.getSampleRate());
 }
 if (event.getAudioSamples().getNumSamples() > 0) {
 IAudioSamples out = IAudioSamples.make(samples.getNumSamples(), samples.getChannels());
 audioResampler.resample(out, samples, samples.getNumSamples());

 AudioSamplesEvent asc = new AudioSamplesEvent(event.getSource(), out, event.getStreamIndex());
 super.onAudioSamples(asc);
 out.delete();
 }
 }

 @Override
 public void run() {
 writer = ToolFactory.makeWriter(outputFile.getAbsolutePath(), reader);
 this.addListener(writer);
 while (reader.readPacket() == null) {
 }
 }

}

I hope this code canĀ  help you, and i’m looking forward for more feedback.

Use Java to convert any media type to FLV with Xuggler

I had the following issue: I wanted to convert any media files the users might upload to my web app to FLV, in order to play them inside my flash player.

JMF (Java Media Framework) doesn’t support conversion to FLV. After some minutes, i found Xuggler.

After following the documentation, i wrote a conversor, that didn’t work.

My first error message was:

ERROR org.ffmpeg – [libmp3lame @ 0x4334a70] flv does not support that sample rate, choose from (44100, 22050, 11025).

I don’t understand why they don’t do this automatically in their framework, but fact was I had to make an audio-resampler.

I started by writing a conversor that extends MediaToolAdapter

// VideoConverter.java
private IAudioResampler audioResampler = null;
@Override
public void onAudioSamples(IAudioSamplesEvent event) {
  IAudioSamples samples = event.getAudioSamples();
  if (audioResampler == null) {
    audioResampler = IAudioResampler.make(2, samples.getChannels(), 44100, samples.getSampleRate());
  }
  if (event.getAudioSamples().getNumSamples() > 0) {
    IAudioSamples out = IAudioSamples.make(samples.getNumSamples(), samples.getChannels());
    audioResampler.resample(out, samples, samples.getNumSamples());

    AudioSamplesEvent asc = new AudioSamplesEvent(event.getSource(), out, event.getStreamIndex());
    super.onAudioSamples(asc);
    out.delete();
  }
}
@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);
  }
  super.onAddStream(event);
}

(I got this from here)

But still it didn’t work, as i kept getting the following error:

Exception in thread “main” java.lang.RuntimeException: failed to encode audio
at com.xuggle.mediatool.MediaWriter.encodeAudio(MediaWriter.java:862)
at com.xuggle.mediatool.MediaWriter.onAudioSamples(MediaWriter.java:1448)

My last clue was to convert the video was well, resulting in the following conversor:

private IVideoResampler videoResampler = null;
private IAudioResampler audioResampler = null;

@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);
  } else if (streamCoder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) {
    streamCoder.setWidth(VIDEO_WIDTH);
    streamCoder.setHeight(VIDEO_HEIGHT);
  }
  super.onAddStream(event);
}

@Override
public void onVideoPicture(IVideoPictureEvent event) {
  IVideoPicture pic = event.getPicture();
  if (videoResampler == null) {
    videoResampler = IVideoResampler.make(VIDEO_WIDTH, VIDEO_HEIGHT, pic.getPixelType(), pic.getWidth(), pic.getHeight(), pic.getPixelType());
  }
  IVideoPicture out = IVideoPicture.make(pic.getPixelType(), VIDEO_WIDTH, VIDEO_HEIGHT);
  videoResampler.resample(out, pic);

  IVideoPictureEvent asc = new VideoPictureEvent(event.getSource(), out, event.getStreamIndex());
  super.onVideoPicture(asc);
  out.delete();
}

@Override
public void onAudioSamples(IAudioSamplesEvent event) {
  IAudioSamples samples = event.getAudioSamples();
  if (audioResampler == null) {
    audioResampler = IAudioResampler.make(2, samples.getChannels(), 44100, samples.getSampleRate());
  }
  if (event.getAudioSamples().getNumSamples() > 0) {
  IAudioSamples out = IAudioSamples.make(samples.getNumSamples(), samples.getChannels());
  audioResampler.resample(out, samples, samples.getNumSamples());

  AudioSamplesEvent asc = new AudioSamplesEvent(event.getSource(), out, event.getStreamIndex());
  super.onAudioSamples(asc);
  out.delete();
  }
}

After writing this conversor, the only thing left to do was to configure the listeners:

IMediaReader reader = ToolFactory.makeReader(inputFile.getAbsolutePath());
reader.addListener(conversor);

IMediaWriter writer = ToolFactory.makeWriter(outputFile.getAbsolutePath(), reader);
writer.addAudioStream(1, 0, 2, 44100);
writer.addVideoStream(0, 0, VIDEO_WIDTH, VIDEO_HEIGHT);
conversor.addListener(writer);
while (running && reader.readPacket() == null) {

//do nothing


}
<pre>

I tested this code using as input flv, mp4, avi, mov and wmv, and they all worked fine. I hope this code will help you as it helped me. If you have any questions or suggestions, please, don’t hesitate in getting in touch with me.