Package net.sf.fmj.media

Source Code of net.sf.fmj.media.BufferQueueInputStream

/**
*
*/
package net.sf.fmj.media;

import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.media.Buffer;

import net.sf.fmj.utility.LoggerSingleton;

import com.lti.utils.synchronization.ProducerConsumerQueue;

/**
* Turns a queue of Buffer objects into an InputStream.
* @author Ken Larson
*
*/
public class BufferQueueInputStream extends InputStream
{
  private static final Logger logger = LoggerSingleton.logger;

  // TODO: we have to be careful about buffering up too much, on a large file, we can
  // run out of heap space.
  private final ProducerConsumerQueue q;

  private static final int DEFAULT_QUEUE_SIZE = 20;

  public BufferQueueInputStream()
  {  this(DEFAULT_QUEUE_SIZE);
  }
 
  public BufferQueueInputStream(int qSize)
  {
    this.q = new ProducerConsumerQueue(qSize);
  }
 
  public BufferQueueInputStream(ProducerConsumerQueue q)
  {
    this.q = q;
  }
 
  private boolean trace = false;
 
  public void setTrace(boolean value)
  {  this.trace = value;
  }
 
  public boolean put(Buffer b)
  {  return put(b, true);
  }
 
  public void blockingPut(Buffer b)
  {  blockingPut(b, true);
  }
 
  public boolean put(Buffer b, boolean clone)
  {
    return put(b, false, clone);
  }
 
  public void blockingPut(Buffer b, boolean clone)
  {
    put(b, true, clone);
  }
 
  /** Note: buffers should be cloned before passing in. Returns false if no room. */
  private boolean put(Buffer b, boolean block, boolean clone)
  {
    if (b.getLength() == -1)
      throw new IllegalArgumentException();
    if (!(b.getData() instanceof byte[]))
      throw new IllegalArgumentException("Expected byte array: " + b.getData());
    if (b.isEOM())
    {  logger.fine("putting EOM buffer");
    }
    else
    {
      if (b.getLength() == 0)
      {  if (trace) logger.fine("Skipping zero length buffer, not adding to queue");
        return true;
      }
      if (b.isDiscard())
      {  if (trace) logger.fine("Skipping discard buffer, not adding to queue");
        return true;
      }
    }
   
    if (trace) logger.fine(this + " BufferQueueInputStream.put: Putting buffer, length=" + b.getLength() + " eom=" + b.isEOM());
    try
    {
      synchronized (q)
      {
        if (!block && q.isFull())
          return false;
        available += b.getLength();
        q.put(clone ? (Buffer) b.clone() : b);
        if (trace) logger.fine(this + " put: available=" + available);
        return true;
      }
     
    } catch (InterruptedException e)
    {
      logger.log(Level.WARNING, "" + e, e);
      throw new RuntimeException(e);
    }
  }
 
  private Buffer buffer;
  private int available = 0// keep track of # of available bytes, in case available() is called.  Must be synchronized on q to use.
 
  private void fillBuffer() throws IOException
  {
    try
    {

      synchronized (q)
      {
     
        do
        {
          if (buffer != null)
          {
            if (buffer.isEOM())
              return;
           
            if (buffer.getLength() > 0)
              return;   // still have data in buffer
          }
          // TODO: any fields to set?
 
          buffer = (Buffer) q.get();
          if (trace) logger.fine(this + " Getting buffer: " + buffer.getLength());
         
          if (buffer.getLength() == 0 && !buffer.isDiscard())
            if (trace) logger.fine("Skipping zero-length buffer in queue");
         
        }
        while (buffer.isDiscard() || buffer.getLength() == 0);
      }
   
    } catch (InterruptedException e)
    {
      logger.log(Level.WARNING, "" + e, e);
      throw new InterruptedIOException();
    }
  }
 
  @Override
  public int available()
  {
    synchronized (q)
    {
      if (trace) logger.fine(this + " available: available=" + available);

      return available;
    }
  }
 
  //@Override
  @Override
  public int read() throws IOException
  {
    // TODO: how do we detect IOException?
    fillBuffer();
    if (buffer.getLength() <= 0 && buffer.isEOM()) // TODO: will always be EOM if length is 0
    if (trace) logger.fine(this + " BufferQueueInputStream.read: returning -1");
      return -1;
    }
    final byte[] data = (byte[]) buffer.getData();
    final int result = data[buffer.getOffset()] & 0xff;
    buffer.setOffset(buffer.getOffset() + 1);
    buffer.setLength(buffer.getLength() - 1);
    synchronized (q)
    {
      available -= 1;
      if (trace) logger.fine(this + " read: available=" + available);

    }
   
    if (trace) logger.fine(this + " BufferQueueInputStream.read: returning " + result);
   
    return result;
   
  }

  //@Override
  @Override
  public int read(byte[] b, int off, int len) throws IOException
  {
    // TODO: how do we detect IOException?
    fillBuffer();
    if (buffer.getLength() <= 0 && buffer.isEOM()) // TODO: will always be EOM if length is 0
    if (trace) logger.fine(this + " BufferQueueInputStream.read: returning -1");
      return -1;
      // TODO: how can buffer.getLength() == -1?
    }
    final byte[] data = (byte[]) buffer.getData();
    if (data == null)
      throw new NullPointerException("Buffer has null data.  length=" + buffer.getLength() + " offset=" + buffer.getOffset());

    int lengthToCopy = buffer.getLength() < len ? buffer.getLength() : len;
    if (trace) logger.fine(this + " BufferQueueInputStream.read: lengthToCopy=" + lengthToCopy + " buffer.getLength()=" + buffer.getLength() + " buffer.getOffset()=" + buffer.getOffset() + " b.length=" + b.length + " len=" + len + " off=" + off);
    System.arraycopy(data, buffer.getOffset(), b, off, lengthToCopy);
    buffer.setOffset(buffer.getOffset() + lengthToCopy);
    buffer.setLength(buffer.getLength() - lengthToCopy);

    synchronized (q)
    {
      available -= lengthToCopy;
      if (trace) logger.fine(this + " read: available=" + available);

    }
   
    if (trace) logger.fine(this + " BufferQueueInputStream.read[]: returning " + lengthToCopy);

   
    return lengthToCopy;
  }


}
TOP

Related Classes of net.sf.fmj.media.BufferQueueInputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.