JyotsnaT / xuggle

Automatically exported from code.google.com/p/xuggle
0 stars 0 forks source link

Xuggler crashes if you attempt call IContainer.writeHeader() with no streams set up. #97

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Pablo provided test program:

package poc;

import java.io.File;
import java.nio.ByteBuffer;
import java.util.ArrayList;

import org.junit.Test;

import com.xuggle.ferry.IBuffer;
import com.xuggle.xuggler.IAudioSamples;
import com.xuggle.xuggler.ICodec;
import com.xuggle.xuggler.IContainer;
import com.xuggle.xuggler.IPacket;
import com.xuggle.xuggler.IStreamCoder;
import com.xuggle.xuggler.IAudioSamples.Format;

public class NewProcessingTest
{
  private static final String INPUT_FILE =
"/home/aclarke/Work/xuggle/java/xuggle-xuggler/test/fixtures/ping.mp3";
  private static final String OUTPUT_FILE = "/tmp/out.mp3";

  private Format format;

  private ArrayList<byte[]> audioData;

  @Test
  public void runTest()
  {
    audioData = new ArrayList<byte[]>();

    long starttime;

    System.out.println("Prepearing to start reading process");

    starttime = System.currentTimeMillis();

    readAudioSamples();

    System.out.println("Reading process completed in " +
(System.currentTimeMillis() - starttime) + " ms");

    System.out.println("Prepearing to start data processing process");

    starttime = System.currentTimeMillis();

    processAudioSamples();

    System.out.println("Processing process completed in " +
(System.currentTimeMillis() - starttime) + " ms");

    System.out.println("Prepearing to start writing process");

    starttime = System.currentTimeMillis();

    writeAudioSamples();

    System.out.println("Writing process completed in " +
(System.currentTimeMillis() - starttime) + " ms");

    audioData.clear();
  }

  private void readAudioSamples()
  {
    IContainer container = openContainer(new File(INPUT_FILE),
IContainer.Type.READ);

    IStreamCoder streamCoder = getStreamCoderFromContainer(container,
ICodec.Type.CODEC_TYPE_AUDIO);

    int retval;
    int offset;

    IPacket packet = IPacket.make();
    IAudioSamples samples = IAudioSamples.make(1024,
streamCoder.getChannels());

    while ( container.readNextPacket(packet) >= 0 )
    {
      retval = 0;
      offset = 0;

      while ( offset < packet.getSize() )
      {
        retval = streamCoder.decodeAudio(samples, packet, offset);

        if ( retval <= 0 )
          throw new RuntimeException("Could not decode audio");

        offset += retval;

        addSample(samples);

        //samples.delete();
        samples = IAudioSamples.make(1024, streamCoder.getChannels());
      }

      System.gc();

      packet = IPacket.make();
    }

    closeContainer(container);
  }

  private void processAudioSamples()
  {
    // TODO: Do something
  }

  private void writeAudioSamples()
  {
    IContainer container = openContainer(new File(OUTPUT_FILE),
IContainer.Type.WRITE);

    IStreamCoder streamCoder = getStreamCoderFromContainer(container,
ICodec.Type.CODEC_TYPE_AUDIO);

    int retval;
    int offset;

    IPacket packet = IPacket.make();
    IAudioSamples samples;

    long ts = 0;

    for ( byte[] data : audioData )
    {
      samples = IAudioSamples.make(1024, streamCoder.getChannels());
      samples.setTimeBase(streamCoder.getTimeBase());
      samples.setTimeStamp(ts);
      samples.setPts(ts);

      IBuffer buffer = samples.getData();
      ByteBuffer rawBytes = buffer.getByteBuffer(0, buffer.getBufferSize());

      rawBytes.put(data);
      rawBytes = null;

      samples.setComplete(true, samples.getNumSamples(),
streamCoder.getSampleRate(), streamCoder.getChannels(), format, ts);

      retval = 0;
      offset = 0;

      while ( offset < samples.getNumSamples() )
      {
        retval = streamCoder.encodeAudio(packet, samples, offset);

        if ( retval <= 0 )
          throw new RuntimeException("Could not encode audio");

        offset += retval;

        if ( packet.isComplete() )
        {                               
          retval = container.writePacket(packet);

          if ( retval < 0 )
            throw new RuntimeException("Could not write output packet");

          break;
        }
      }

      ts += 4702;

      //packet.delete();

      System.gc();

      packet = IPacket.make();
    }

    closeContainer(container);
  }

  private IContainer openContainer(File file, IContainer.Type containerType)
  {
    IContainer container = IContainer.make();

    if (container.open(file.getAbsolutePath(), containerType, null) < 0)
      throw new RuntimeException("Could not open container for file " +
file.getAbsoluteFile());

    for ( int i = 0 ; i < container.getNumStreams() ; i++ )
    {
      IStreamCoder streamCoder = container.getStream(i).getStreamCoder();

      if ( streamCoder.open() < 0 )
        throw new RuntimeException("Could not open coder for type " +
streamCoder.getCodecType());
    }

    if ( container.getType() == IContainer.Type.WRITE )
    {
      if ( container.writeHeader() < 0 )
        throw new RuntimeException("Could not write file header");
    }

    return container;
  }

  private void closeContainer(IContainer container)
  {
    if ( container.getType() == IContainer.Type.WRITE )
    {
      if ( container.writeTrailer() < 0 )
        throw new RuntimeException("Could not write file trailer");
    }

    for ( int i = 0 ; i < container.getNumStreams() ; i++ )
    {
      if ( container.getStream(i).getStreamCoder().close() < 0 )
        throw new RuntimeException("Could not close coder");
    }

    if ( container.close() < 0 )
      throw new RuntimeException("Could not close container");
  }

  private IStreamCoder getStreamCoderFromContainer(IContainer container,
ICodec.Type codecType)
  {
    for ( int i = 0 ; i < container.getNumStreams() ; i++ )
    {
      IStreamCoder streamCoder = container.getStream(i).getStreamCoder();

      if ( streamCoder.getCodecType() == codecType )
      {
        return streamCoder;
      }
    }

    throw new RuntimeException("Could not find stream coder for type " +
codecType);
  }

  private void addSample(IAudioSamples samples)
  {
    byte[] data = samples.getData().getByteArray(0, samples.getSize());

    audioData.add(data);

    if ( format == null )
    {
      format = samples.getFormat();
    }
  }
}

Original issue reported on code.google.com by art.cla...@gmail.com on 7 Apr 2009 at 11:54

GoogleCodeExporter commented 9 years ago
Causes Java to crash so it's critical (even though the actual problem is user 
error
since the output container has no streams set up).

Original comment by art.cla...@gmail.com on 8 Apr 2009 at 12:00

GoogleCodeExporter commented 9 years ago
The issue was that writeHeader() wasn't checking to make sure there were streams
already added to the container.  When writing FLV files this didn't matter, but 
the
FFMPEG MP3 muxer would core dump without at least one stream.

So now we don't actually call av_write_header if we don't have at least one 
stream as
a work around.  I think that's the right fix.

There is a native and a java unit test checked in with the fix in r334

Original comment by art.cla...@gmail.com on 8 Apr 2009 at 12:25