/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2014, OpenSpace Solutions LLC. All Right Reserved.
*/
package com.chiorichan.dvr;
import com.chiorichan.Loader;
import com.chiorichan.command.Command;
import com.chiorichan.command.CommandSender;
import com.chiorichan.configuration.file.FileConfiguration;
import com.chiorichan.configuration.file.YamlConfiguration;
import com.chiorichan.dvr.registry.InputRegistry;
import com.chiorichan.http.HttpResponse;
import com.chiorichan.http.HttpResponseStage;
import com.chiorichan.plugin.java.JavaPlugin;
import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.ds.v4l4j.V4l4jDriver;
import com.github.sarxos.webcam.log.WebcamLogConfigurator;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.imageio.ImageIO;
public class DVRLoader extends JavaPlugin
{
public static boolean isRunning = false;
private EventListener listener = new EventListener();
private static Executor executor = null;
public static YamlConfiguration config;
public static DVRLoader instance;
static
{
// If we are running on a Linux system, we want to use the Video4Linux4Java driver.
if ( System.getProperty( "os.name" ).toLowerCase().contains( "linux" ) )
Webcam.setDriver( new V4l4jDriver() );
}
public DVRLoader()
{
WebcamLogConfigurator.configure( DVRLoader.class.getClassLoader().getResourceAsStream( "com/chiorichan/dvr/logback.xml" ) );
Loader.getLogger().info( "You are running OS: " + System.getProperty( "os.name" ) );
// XXX: Get command is broken. This needs to get fixed in the main program.
//getCommand( "dvr" ).setExecutor( new CommandHandler( this ) );
instance = this;
new InputRegistry();
}
@Override
public boolean onCommand( CommandSender sender, Command command, String label, String[] args )
{
if ( command.getName().equalsIgnoreCase( "dvr" ) )
{
if ( args.length < 1 )
{
sender.sendMessage( "You must define a subcommand." );
return true;
}
switch ( args[0].toLowerCase() )
{
case "unload":
preunload();
return true;
}
}
return false;
}
public void startMultipart( final HttpResponse rep, int channel ) throws IOException
{
if ( channel < 0 || channel > InputRegistry.getInputCount() - 1 )
channel = 0;
final int channelNum = channel;
rep.setContentType( "image/jpeg" );
rep.sendMultipart( null );
int _taskId = -1;
class PushTask implements Runnable
{
int id = -1;
@Override
public void run()
{
if ( InputRegistry.get( channelNum ).getLastImage() != null )
try
{
ByteArrayOutputStream bs = new ByteArrayOutputStream();
ImageIO.write( InputRegistry.get( channelNum ).getLastImage(), "JPG", bs );
bs.flush();
byte[] bss = bs.toByteArray();
bs.close();
rep.sendMultipart( bss );
}
catch ( IOException e )
{
if ( e.getMessage().toLowerCase().equals( "stream is closed" ) || e.getMessage().toLowerCase().equals( "broken pipe" ) )
{
Loader.getScheduler().cancelTask( id );
try
{
rep.closeMultipart();
}
catch ( Exception e1 )
{
}
}
Loader.getLogger().warning( e.getMessage(), e );
}
if ( rep.getStage() != HttpResponseStage.MULTIPART )
{
Loader.getScheduler().cancelTask( id );
try
{
rep.closeMultipart();
}
catch ( Exception e1 )
{
}
}
}
public void setId( int _taskId )
{
id = _taskId;
}
}
;
PushTask task = new PushTask();
_taskId = Loader.getScheduler().scheduleSyncRepeatingTask( this, task, 1L, 1L );
task.setId( _taskId );
}
public byte[] grabSnapshot( int channel ) throws IOException
{
if ( channel < 0 || channel > InputRegistry.getInputCount() - 1 )
channel = 0;
ByteArrayOutputStream bs = new ByteArrayOutputStream();
ImageIO.write( InputRegistry.get( channel ).getLastImage(), "PNG", bs );
bs.flush();
byte[] bss = bs.toByteArray();
bs.close();
return bss;
}
@Override
public void onEnable()
{
isRunning = true;
File file = new File( getDataFolder(), "config.yml" );
config = YamlConfiguration.loadConfiguration( file );
if ( config.getString( "config.storage", "null" ).toLowerCase().equals( "null" ) )
{
try {
config.set( "config.storage", getDataFolder().getAbsoluteFile() );
config.save( file );
}
catch ( IOException ex ) {
ex.printStackTrace();
}
}
//Loader.getPluginManager().registerEvents( listener, this );
InputRegistry.findAllDevices();
InputRegistry.openAllDevices();
}
@Override
public void onDisable()
{
if ( isRunning )
{
isRunning = false;
executor.execute( new PluginShutdownRunnable() );
}
}
public static FileConfiguration getConfiguration()
{
return config;
}
public static Executor getExecutor()
{
if ( executor == null )
executor = Executors.newCachedThreadPool();
return executor;
}
void preunload()
{
if ( isRunning )
{
isRunning = false;
executor.execute( new PluginShutdownRunnable() );
}
}
/**
* Any processes such as the unloading of all devices that might block are placed in this class.
*/
class PluginShutdownRunnable implements Runnable
{
@Override
public void run()
{
// Signal the InputRegistry of unloading and wait.
InputRegistry.destroyAllDevices();
}
}
}