package com.example.sagivtechtemplate;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

import android.os.Bundle;
import android.os.Message;
import android.util.Log;

//OpenCV related imports.
import org.opencv.utils.*;
import org.opencv.android.*;
import org.opencv.core.*;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;


public class SagivTechProcessingThread extends Thread {
	// Native declarations
	public native int OpenCVBgraToGray(long pInputMatrix, long pOutputMatrix);
	public native int oclInitialize(int w, int h, ByteBuffer bbKernelCode);
	public native int oclRun(long matInput, ByteBuffer output);

	// SagivTechProcessingThread data members
	private final String TAG = "SagivTechProcessingThread";
	private int h_, w_;
	public boolean bRun_;
	public boolean bRunOpenCV_;
	public boolean bRunOpenCL_;
	private boolean bOpenCLInitialized_;
	private int lastInputH_, lastInputW_;
	public 	Mat matResult = null;
	private Mat matRGBInput = null;
	private SagivTechMainActivity mainActivity_ = null;
	public  static final int MAX_FRAMES_QUEUE_SIZE = 100;
	public BlockingQueue<Mat> queueFrames_ = new ArrayBlockingQueue<Mat>(MAX_FRAMES_QUEUE_SIZE, true);
    ByteBuffer bbOpenCLKernelCode = null;

	// CTor.
	public SagivTechProcessingThread(SagivTechMainActivity mainActivity, int h, int w) {
		h_ = h;
		w_ = w;
		lastInputH_ = h_;
		lastInputW_ = w_;
		bRun_ = false;
		bRunOpenCV_ = false;
		bRunOpenCL_ = false;
		bOpenCLInitialized_ = false;
		mainActivity_ = mainActivity;
	}

	private void initializeOpenCL() {
		bbOpenCLKernelCode = getProgramBuffer("SagivTechTemplateSample.cl");
		oclInitialize(w_, h_, bbOpenCLKernelCode);
	}
	
	public void pushFrame(Mat matInput) {
		synchronized(queueFrames_) {
			if (queueFrames_.size() > (float)MAX_FRAMES_QUEUE_SIZE * 0.9) {
				Log.v(TAG, "Clearing queueFrames object as it reached its limit");
				queueFrames_.clear();
			}
			try {
				queueFrames_.put(matInput);
			} catch (InterruptedException ie) {
				Log.v(TAG, "Failed to push frame to queue");
			}
		}
	}
	
	public void run() {
		try {
			while (true) {
				
				if (!bRun_) {
					Thread.sleep(3);
					continue;
				}

				Mat matInput = null;
				if (queueFrames_.size() > 0) {
					synchronized(queueFrames_) {
						matInput = queueFrames_.take();
					}
				}
				else 
					continue;

				// Check if resolution changed.
				if ((0 == matInput.rows()) || (0 == matInput.cols()))
						continue;
				if ((matInput.rows() != lastInputH_) || (matInput.cols() != lastInputW_)) {
					matResult = new Mat(matInput.rows(), matInput.cols(), CvType.CV_8UC4);
					matRGBInput = new Mat(matInput.rows(), matInput.cols(), CvType.CV_8UC3);
					Log.v("TAG", "Creating new matrix...[" + matResult.toString());
					lastInputH_ = matInput.rows();
					lastInputW_ = matInput.cols();
					w_ = lastInputW_;
					h_ = lastInputH_;
				}

				Message msg;
				msg = mainActivity_.mainHandler.obtainMessage();
				msg.what = 0;

				//Imgproc.cvtColor(matInput, matRGBInput, Imgproc.COLOR_BGRA2RGB);
				if (bRunOpenCV_) {
					// Call the OpenCV algorithm to convert from BGRA to Gray.
					OpenCVBgraToGray(matInput.getNativeObjAddr(), matResult.getNativeObjAddr());
				}
				if (bRunOpenCL_) {
					// Initialize OpenCL stuff.
					if (!bOpenCLInitialized_) {
						initializeOpenCL();
						bOpenCLInitialized_ = true;						
					}
                    ByteBuffer outputBuffer = ByteBuffer.allocateDirect(matInput.rows() * matInput.cols() * 4);
                    oclRun(matInput.getNativeObjAddr(), outputBuffer);

                    outputBuffer.rewind();
                    matResult.put(0, 0, outputBuffer.array());
				}

				// Synchronize on the main activity object and send an update to the UI thread to update the image.
				synchronized(mainActivity_) {
					//Imgproc.cvtColor(matResult, matResult, Imgproc.COLOR_RGBA2BGR);
					msg.obj = matResult.clone();
				}
				mainActivity_.mainHandler.sendMessage(msg);
				
			}
		} catch (Exception e) {
			Log.e(TAG, "run caught interrupted exception. " + e.toString());
		}			
	}	

	// Helper function to read the OpenCL kernel files from the assest folder.
    private ByteBuffer getProgramBuffer(String sFileName) {
		String line;
		InputStream stream;
		byte[] programBytes;
		StringBuilder program = new StringBuilder();
		ByteBuffer buffer = null;

		try {
			stream = mainActivity_.getResources().getAssets().open(sFileName);
			BufferedReader br = new BufferedReader(new InputStreamReader(stream));
			while((line = br.readLine()) != null) {
				program.append(line + "\n");
				Log.e(TAG, line);
			}
			stream.close();
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		program.append("\0");

		// Create ByteBuffer
		try {
			programBytes = program.toString().getBytes("UTF-8");
			buffer = ByteBuffer.allocateDirect(programBytes.length);
			buffer.put(programBytes);
			buffer.rewind();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	
	return buffer;
	}
	
}

Legal Disclaimer:

You understand that when using the Site you may be exposed to content from a variety of sources, and that SagivTech is not responsible for the accuracy, usefulness, safety or intellectual property rights of, or relating to, such content and that such content does not express SagivTech’s opinion or endorsement of any subject matter and should not be relied upon as such. SagivTech and its affiliates accept no responsibility for any consequences whatsoever arising from use of such content. You acknowledge that any use of the content is at your own risk.