<?php

/**
 * @author Gernot Walzl
 */
class FileSystemObject {

    private static 
$instance NULL;

    protected function 
__construct() {}

    public static function 
get_instance() {
        if (
self::$instance === NULL) {
            
self::$instance = new self();
        }
        return 
self::$instance;
    }

    function 
get_dirs() {
        
$result null;
        if (
$handle opendir(dirname(__FILE__))) {
            
$result = array();
            while (
false !== ($file readdir($handle))) {
                if (
substr($file01) != '.') {
                    if (
is_dir($file)) {
                        
array_push($result$file);
                    }
                }
            }
            
closedir($handle);
            
sort($result);
        }
        return 
$result;
    }

    function 
is_good_filename($filename$exts=array()) {
        
$result false;
        if (
substr($filename01) != '.') {
            if (empty(
$exts)) {
                
$result true;
            } else {
                foreach (
$exts as $ext) {
                    if (
substr($filename, -strlen($ext)) === $ext) {
                        
$result true;
                        break;
                    }
                }
            }
        }
        return 
$result;
    }

    function 
get_files($path='.'$ext=array()) {
        
$result null;
        if (
$handle opendir(dirname(__FILE__).'/'.$path)) {
            
$result = array();
            while (
false !== ($file readdir($handle))) {
                if (
$this->is_good_filename($file)) {
                    if (
is_file($path.'/'.$file) &&
                            
is_readable($path.'/'.$file)) {
                        
array_push($result$path.'/'.$file);
                    }
                }
            }
            
closedir($handle);
            
sort($result);
        }
        return 
$result;
    }

}


/**
 * @author Gernot Walzl
 */
class CameraHTML {

    protected 
$fso NULL;

    public function 
__construct() {
        
$this->fso FileSystemObject::get_instance();
    }

    function 
println($msg) {
        print(
$msg."\n");
    }

    function 
print_head() {
        
$this->println('<!DOCTYPE html>');
        
$this->println('<html>');
        
$this->println('<head>');
        
$this->println('<meta charset="utf-8" />');
        
$this->println('<title>Camera</title>');
        
$this->println('<link rel="stylesheet" type="text/css" '.
                       
'media="screen" href="screen.css" />');
        
$this->println('</head>');
        
$this->println('<body>');
    }

    function 
print_dirs() {
        
$dirs $this->fso->get_dirs();
        if (!empty(
$dirs)) {
            
$this->println('<ul>');
            for (
$cnt count($dirs)-1$cnt >= 0$cnt--) {
                
$dir $dirs[$cnt];
                
$this->println('<li>');
                
$this->println('<a href="'.$_SERVER['PHP_SELF'].
                        
'?dir='.urlencode($dir).'">'.basename($dir).'</a>');
                
$this->println('</li>');
            }
            
$this->println('</ul>');
        }
    }

    function 
get_time_from_name($filepath) {
        
$filename basename($filepath);
        
$hour substr($filename112);
        
$minute substr($filename132);
        
$second substr($filename152);
        return 
$hour.':'.$minute.':'.$second;
    }

    function 
print_mjpg_files($path='.') {
        
$exts = array('avi''mkv''mjpg');
        
$files $this->fso->get_files($path$exts);
        if (!empty(
$files)) {
            
$this->println('<table>');
            for (
$cnt count($files)-1$cnt >= 0$cnt--) {
                
$file $files[$cnt];
                
$this->println('<tr>');
                
$this->println('<td>'.basename($file).'</td>');
                
$this->println('<td><a href="'.$_SERVER['PHP_SELF'].
                        
'?play='.urlencode($file).'&fps=1">Play 1fps</a></td>');
                
$this->println('<td><a href="'.$_SERVER['PHP_SELF'].
                        
'?play='.urlencode($file).'&fps=5">Play 5fps</a></td>');
                
$this->println('<td><a href="'.$_SERVER['PHP_SELF'].
                        
'?play='.urlencode($file).'&fps=25">Play 25fps</a></td>');
                
$this->println('<td><a href="'.$file.'" download>Download</a></td>');
                
$this->println('</tr>');
            }
            
$this->println('</table>');
        }
    }

    function 
print_foot() {
        
$this->println('</body>');
    }

}


/**
 * @author Gernot Walzl
 */
class MJPEGStreamer {

    function 
send_jpeg($data) {
        print(
"--jpgboundary\n");
        print(
"Content-type: image/jpeg\n");
        print(
"Content-length: ".strlen($data)."\n\n");
        print(
$data."\n");
        
flush();
    }

    function 
stream_mjpeg($path$fps=10) {
        
set_time_limit(0);
        
header('Content-type: multipart/x-mixed-replace; boundary=jpgboundary');

        
$frametime_us 1000000/$fps;

        
$jpeg_begin hex2bin('ffd8');
        
$jpeg_end hex2bin('ffd9');
        
$jpeg_content false;
        
$jpeg_data '';

        if (
$handle fopen($path'rb')) {
            while (!
feof($handle)) {
                
$contents fread($handle4096);
                if (
$jpeg_content) {
                    
$pos_jpeg_stop strpos($contents$jpeg_end);
                    if (
$pos_jpeg_stop) {
                        
$jpeg_data .= substr($contents0$pos_jpeg_stop+2);
                        
$jpeg_content false;
                        
$this->send_jpeg($jpeg_data);
                        
usleep($frametime_us);
                    } else {
                        
$jpeg_data .= $contents;
                    }
                }
                if (!
$jpeg_content) {
                    
$pos_jpeg_start strpos($contents$jpeg_begin);
                    if (
$pos_jpeg_start) {
                        
$jpeg_content true;
                        
$jpeg_data substr($contents$pos_jpeg_start);
                    }
                }
            }
            
fclose($handle);
        }
    }

}


if (!empty(
$_GET['play'])) {
    
$file stripslashes(urldecode($_GET['play']));
    if (!
stristr($file'..') &&
            
file_exists(dirname(__FILE__).'/'.$file)) {
        
$fps 10;
        if (!empty(
$_GET['fps'])) {
            
$fps intval($_GET['fps']);
        }
        
$streamer = new MJPEGStreamer();
        
$streamer->stream_mjpeg($file$fps);
    }
} else {
    
$html = new CameraHTML();
    
$html->print_head();
    
$html->println('<div id="header">');
    
$html->println('<h1>Camera</h1>');
    
$html->println('<p><a href="http://'.$_SERVER['SERVER_ADDR'].':8000/cam.mjpg">Live View</a></p>');
    
$html->println('</div>');
    
$html->println('<div id="recordings">');
    
$html->println('<h2>Recordings</h2>');
    
$html->print_dirs();
    
$html->println('</div>');
    if (!empty(
$_GET['dir'])) {
        
$dir stripslashes(urldecode($_GET['dir']));
        if (!
stristr($dir'..') &&
                
file_exists(dirname(__FILE__).'/'.$dir))  {
            
$html->println('<div id="filelist">');
            
$html->println('<h3>'.basename($dir).'</h3>');
            
$html->print_mjpg_files($dir);
            
$html->println('</div>');
        }
    }
    
$html->print_foot();
}

?>