Convert Audio With Xuggler

I am trying to convert aac / wav / wma audio files to mp3 from Xuggler in Java.

Unfortunately, I have a big loss in quality. The size of my input file is about 7 MB, and the size of my output file is only 1.5 MB.

The sampling frequency is set to 44100 Hz, are there any other parameters for the installation?

Thank you for your responses.

if (args.length <= 1) throw new IllegalArgumentException("must pass an input filename and output filename as argument"); IMediaWriter writer = ToolFactory.makeWriter(args[1]); String filename = args[0]; // Create a Xuggler container object IContainer container = IContainer.make(); // Open up the container if (container.open(filename, IContainer.Type.READ, null) < 0) throw new IllegalArgumentException("could not open file: " + filename); // query how many streams the call to open found int numStreams = container.getNumStreams(); // and iterate through the streams to find the first audio stream int audioStreamId = -1; IStreamCoder audioCoder = null; for(int i = 0; i < numStreams; i++) { // Find the stream object IStream stream = container.getStream(i); // Get the pre-configured decoder that can decode this stream; IStreamCoder coder = stream.getStreamCoder(); if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_AUDIO) { audioStreamId = i; audioCoder = coder; audioCoder.setBitRate(container.getBitRate()); break; } } if (audioStreamId == -1) throw new RuntimeException("could not find audio stream in container: "+filename); /* We read only AAC file for the moment */ if(audioCoder.getCodecID() != ICodec.ID.CODEC_ID_AAC && audioCoder.getCodecID() != ICodec.ID.CODEC_ID_WAVPACK && audioCoder.getCodecID() != ICodec.ID.CODEC_ID_WMAV1 && audioCoder.getCodecID() != ICodec.ID.CODEC_ID_WMAV2 && audioCoder.getCodecID() != ICodec.ID.CODEC_ID_WMAPRO && audioCoder.getCodecID() != ICodec.ID.CODEC_ID_WMAVOICE) { System.out.println("Read only AAC, WAV or WMA files"); System.exit(1); } audioCoder.setSampleFormat(IAudioSamples.Format.FMT_S16); /* * Now we have found the audio stream in this file. Let open up our decoder so it can * do work. */ if (audioCoder.open() < 0) throw new RuntimeException("could not open audio decoder for container: "+filename); int streamIndex = writer.addAudioStream(0, 0, audioCoder.getChannels(), audioCoder.getSampleRate()); System.out.println("audio Frame size : "+audioCoder.getAudioFrameSize()); /* * Now, we start walking through the container looking at each packet. */ IPacket packet = IPacket.make(); while(container.readNextPacket(packet) >= 0) { /* * Now we have a packet, let see if it belongs to our audio stream */ if (packet.getStreamIndex() == audioStreamId) { /* * We allocate a set of samples with the same number of channels as the * coder tells us is in this buffer. * * We also pass in a buffer size (1024 in our example), although Xuggler * will probably allocate more space than just the 1024 (it not important why). */ IAudioSamples samples = IAudioSamples.make(512, audioCoder.getChannels(),IAudioSamples.Format.FMT_S16 ); /* * A packet can actually contain multiple sets of samples (or frames of samples * in audio-decoding speak). So, we may need to call decode audio multiple * times at different offsets in the packet data. We capture that here. */ int offset = 0; /* * Keep going until we've processed all data */ while(offset < packet.getSize()) { int bytesDecoded = audioCoder.decodeAudio(samples, packet, offset); if (bytesDecoded < 0) throw new RuntimeException("got error decoding audio in: " + filename); offset += bytesDecoded; /* * Some decoder will consume data in a packet, but will not be able to construct * a full set of samples yet. Therefore you should always check if you * got a complete set of samples from the decoder */ if (samples.isComplete()) { writer.encodeAudio(streamIndex, samples); } } } else { /* * This packet isn't part of our audio stream, so we just silently drop it. */ do {} while(false); } } 
+3
source share
3 answers

I will do something like this:

 public void convertToMP3(File input, File output, int kbps) { //modify on your convenience // create a media reader IMediaReader mediaReader = ToolFactory.makeReader(input.getPath()); // create a media writer IMediaWriter mediaWriter = ToolFactory.makeWriter(output.getPath(), mediaReader); // add a writer to the reader, to create the output file mediaReader.addListener(mediaWriter); // add a IMediaListner to the writer to change bit rate mediaWriter.addListener(new MediaListenerAdapter() { @Override public void onAddStream(IAddStreamEvent event) { IStreamCoder streamCoder = event.getSource().getContainer().getStream(event.getStreamIndex()).getStreamCoder(); streamCoder.setFlag(IStreamCoder.Flags.FLAG_QSCALE, false); streamCoder.setBitRate(kbps); streamCoder.setBitRateTolerance(0); } }); // read and decode packets from the source file and // and dispatch decoded audio and video to the writer while (mediaReader.readPacket() == null); } 

input File (AAC / WAV / WMA) you want to convert and output a new .mp3 file (Xuggler figure from conversion extension).

You can increase the quality of kbps (i.e. by 320 kbps, which must be transmitted to 320,000).

Hope that helps :-)

FYI: for Java projects, you will need to import the following if you have not already done so:

 import com.xuggle.mediatool.MediaListenerAdapter; import com.xuggle.mediatool.event.IAddStreamEvent; import com.xuggle.xuggler.IStreamCoder; 
+6
source

I'm not sure exactly which options and what they do, but look at the javadoc for IStreamCoder . There are other options that you can play with. You can even set flags directly in ffmpeg (which Xuggler uses under it) using the setFlags() method if you want complete control.

0
source

Be careful if you have mp3 with cover art (png), you may end up with errors because you are trying to send a png video stream to an audio stream .. Using ISamples and reading a package with if (packet.getStreamIndex () = = audioStreamId) {} Gives better control over the stream used. check out my full code:

 private static void streamToSource( OutputStream source, Path path ) throws IOException { byte[] buffer = new byte[4096]; PipedInputStream pis = new PipedInputStream( ); PipedOutputStream pos = new PipedOutputStream( pis ); convertToMP3Xuggler( path, pos ); System.out.println( "start streaming" ); int nRead = 0; while ( ( nRead = pis.read( buffer ) ) != -1 ) { source.write( buffer,0 , nRead ); } pis.close( ); System.out.println( "end : " + path ); } private static void convertToMP3Xuggler( Path path, PipedOutputStream pos ) throws FileNotFoundException { // create a media reader // final IMediaReader mediaReader = ToolFactory.makeReader( XugglerIO.map( new FileInputStream( path.toFile( ) ) ) ); // create a media writer // IMediaWriter mediaWriter = ToolFactory.makeWriter( XugglerIO.map( XugglerIO.generateUniqueName( os, ".mp3" ), os ), mediaReader ); IMediaWriter mediaWriter = ToolFactory.makeWriter( XugglerIO.map( pos ) ); // manually set the container format (because it can't detect it by filename anymore) IContainerFormat containerFormat = IContainerFormat.make( ); containerFormat.setOutputFormat( "mp3", null, "audio/mp3" ); mediaWriter.getContainer( ).setFormat( containerFormat ); System.out.println( "file = " + path.toFile( ).toString( ) ); IContainer audioContainer = IContainer.make( ); audioContainer.open( path.toFile( ).toString( ), IContainer.Type.READ, null ); System.out.println( "streams= " + audioContainer.getNumStreams( ) ); System.out.println( "# Duration (ms): " + ( ( audioContainer.getDuration( ) == Global.NO_PTS ) ? "unknown" : "" + audioContainer.getDuration( ) / 1000 ) ); System.out.println( "# File size (bytes): " + audioContainer.getFileSize( ) ); System.out.println( "# Bit rate: " + audioContainer.getBitRate( ) ); int audioStreamId = -1; for ( int i = 0; i < audioContainer.getNumStreams( ); i++ ) { // Find the stream object IStream stream = audioContainer.getStream( i ); // Get the pre-configured decoder that can decode this stream; IStreamCoder coder = stream.getStreamCoder( ); if ( coder.getCodecType( ) == ICodec.Type.CODEC_TYPE_AUDIO ) { audioStreamId = i; break; } } if ( audioStreamId < 0 ) { throw new IllegalArgumentException( "cannot find audio stream in the current file : " + path.toString( ) ); } System.out.println( "found audio stream = " + audioStreamId ); IStreamCoder coderAudio = audioContainer.getStream( audioStreamId ).getStreamCoder( ); if ( coderAudio.open( null, null ) < 0 ) { throw new RuntimeException( "Cant open audio coder" ); } coderAudio.setSampleFormat( IAudioSamples.Format.FMT_S16 ); System.out.println( "bitrate from reading = " + audioContainer.getBitRate( ) ); System.out.println( "bitrate from reading = " + coderAudio.getBitRate( ) ); int streamIndex = mediaWriter.addAudioStream( 0, 0, coderAudio.getChannels( ), coderAudio.getSampleRate( ) ); IStreamCoder writerCoder = mediaWriter.getContainer( ).getStream( streamIndex ).getStreamCoder( ); writerCoder.setFlag( IStreamCoder.Flags.FLAG_QSCALE, false ); writerCoder.setBitRate( BITRATE * 1000 ); writerCoder.setBitRateTolerance( 0 ); System.out.println( "bitrate for output = " + writerCoder.getBitRate( ) ); IPacket packet = IPacket.make( ); runInThread( path, pos, mediaWriter, audioContainer, audioStreamId, coderAudio, streamIndex, packet ); } private static void runInThread( Path path, PipedOutputStream pos, IMediaWriter mediaWriter, IContainer audioContainer, int audioStreamId, IStreamCoder coderAudio, int streamIndex, IPacket packet ) { new Thread( ) { @Override public void run( ) { while ( audioContainer.readNextPacket( packet ) >= 0 ) { /* * Now we have a packet, let see if it belongs to our audio stream */ if ( packet.getStreamIndex( ) == audioStreamId ) { /* * We allocate a set of samples with the same number of channels as the * coder tells us is in this buffer. * We also pass in a buffer size (4096 in our example), although Xuggler * will probably allocate more space than just the 4096 (it not important why). */ IAudioSamples samples = IAudioSamples.make( 4096, coderAudio.getChannels( ), IAudioSamples.Format.FMT_S16 ); /* * A packet can actually contain multiple sets of samples (or frames of samples * in audio-decoding speak). So, we may need to call decode audio multiple * times at different offsets in the packet data. We capture that here. */ int offset = 0; /* * Keep going until we've processed all data */ while ( offset < packet.getSize( ) ) { int bytesDecoded = coderAudio.decodeAudio( samples, packet, offset ); if ( bytesDecoded < 0 ) { System.out.println( "decode error in : " + path + " bytesDecoded =" + bytesDecoded + " offset=" + offset + " packet=" + packet ); break; // throw new RuntimeException( "got error decoding audio in: " + path ); } offset += bytesDecoded; // System.out.println( "pktSize = " + packet.getSize( ) + " offset = " + offset + " samplesComplete = " + samples.isComplete( ) ); /* * Some decoder will consume data in a packet, but will not be able to construct * a full set of samples yet. Therefore you should always check if you * got a complete set of samples from the decoder */ if ( samples.isComplete( ) ) { mediaWriter.encodeAudio( streamIndex, samples ); } } } } coderAudio.close( ); audioContainer.close( ); mediaWriter.close( ); try { pos.close( ); } catch ( IOException e ) { e.printStackTrace( ); } } }.start( ); } 
0
source

Source: https://habr.com/ru/post/1435763/


All Articles