/**
 * This package provides classes to handle video in Processing. The API is compatible with the built-in video library of Processing. 
 * GSVideo uses the multimedia toolkit GStreamer (http://www.gstreamer.net/)  through the gstreamer-java bindings by Wayne Meissener:
 * http://code.google.com/p/gstreamer-java/ 
 * @author Andres Colubri
 * @version 0.4.5
 *
 * Copyright (c) 2008 Andres Colubri
 *
 * This source is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This code is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * A copy of the GNU General Public License is available on the World
 * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also
 * obtain it by writing to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

package codeanticode.gsvideo;
import processing.core.*;

import java.io.*;
import java.nio.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.SynchronousQueue;

import org.gstreamer.*;
import org.gstreamer.elements.*;
import org.gstreamer.Buffer;

import org.gstreamer.elements.CustomSrc;
import org.gstreamer.lowlevel.GstAPI.GstSegmentStruct;

/**
 * This class is intended to injects buffers into the GStreamer pipeline. DOESN'T WORK.
 */
public class GSBufferSrc extends CustomSrc 
{
    PApplet parent;

    private byte[] bufferPixels;
    private int waitTime;
    private SynchronousQueue<ByteBuffer> synchQueue;

    public GSBufferSrc(PApplet parent, SynchronousQueue<ByteBuffer> queue, int wt, int w, int h, String name) 
    {
        super(GSBufferSrc.class, name);
	
        this.parent = parent;
	
        synchQueue = queue;
        waitTime = wt;
        bufferPixels = new byte[w * h * 4];
    }
	
    private void readFully(long offset, long size, Buffer buffer) throws IOException 
    {
        try 
        {
            parent.print("Polling buffer...");
            ByteBuffer poll = (ByteBuffer)synchQueue.poll(waitTime, TimeUnit.MILLISECONDS);
            parent.println("Got buffer.");
	
            poll.rewind();
            poll.get(bufferPixels);
	  
            buffer.getByteBuffer().put(bufferPixels, 0, bufferPixels.length);

            buffer.setOffset(offset);
            buffer.setLastOffset(bufferPixels.length);
            buffer.setTimestamp(ClockTime.NONE);
        } 
        catch (InterruptedException ie) 
        {
            ie.printStackTrace();
            throw new EOFException();
        } 
        catch (NullPointerException ne) 
        {
            ne.printStackTrace();
            throw new EOFException();
        }
    }
    
    @Override
    protected FlowReturn srcFillBuffer(long offset, int size, Buffer buffer) 
    {
        try 
        {            
            readFully(offset, size, buffer);
            return FlowReturn.OK;
        } 
        catch (IOException ex) 
        {
            return FlowReturn.UNEXPECTED;
        }        
    }
	
    @Override
    public boolean srcIsSeekable() 
    {
        return false;
    }
    
    @Override
    protected boolean srcSeek(GstSegmentStruct segment) 
    {
        return true;
    }    
}
