PHP Classes

File: src/PHPVideoToolkit/ProgressHandlerNative.php

Recommend this page to a friend!
  Classes of Oliver Lillie   PHP Video Toolkit   src/PHPVideoToolkit/ProgressHandlerNative.php   Download  
File: src/PHPVideoToolkit/ProgressHandlerNative.php
Role: Class source
Content type: text/plain
Description: Class source
Class: PHP Video Toolkit
Manipulate and convert videos with ffmpeg program
Author: By
Last change: bug fix for empty progress files and data returning empty incorrectly being determined as completed

Signed-off-by: Oliver Lillie <buggedcom@gmail.com>
fixed issue where native progress handler temp files were not being deleted and fix issue where the wrong method of checking if the process had ended was being used
added bug fix workaround for progress handlers where the output file is prematurely deleted. switched end status to ProgressHandlerDefaultData::ENCODING_STATUS_FINISHED to determine when the process has finished rather than completed because completed applies to the encode and not the entire process.
amended native progress handler to also include input and output file information
fixed potential bugs in progress handler completed value where if ffmpeg has finished encoding but the process has not completed errors could occur from trying to get the output of the process. Added progress handler status constants for checking statuses
Merge branch 'refs/heads/multiple-output'

Conflicts:
README.md
src/PHPVideoToolkit/ProgressHandlerOutput.php
src/PHPVideoToolkit/ProgressHandlerPortable.php
fixed small issue of whitespace
updated version in source
Date: 1 year ago
Size: 7,101 bytes
 

Contents

Class file image Download
<?php
   
   
/**
     * This file is part of the PHP Video Toolkit v2 package.
     *
     * @author Oliver Lillie (aka buggedcom) <publicmail@buggedcom.co.uk>
     * @license Dual licensed under MIT and GPLv2
     * @copyright Copyright (c) 2008-2014 Oliver Lillie <http://www.buggedcom.co.uk>
     * @package PHPVideoToolkit V2
     * @version 2.1.7-beta
     * @uses ffmpeg http://ffmpeg.sourceforge.net/
     */
    
   
namespace PHPVideoToolkit;

   
/**
     * @access public
     * @author Oliver Lillie
     * @package default
     */
   
class ProgressHandlerNative extends ProgressHandlerAbstract
   
{
        protected
$_progress_file;
        protected
$_input;
        protected
$_output;
       
        public function
__construct($callback=null, Config $config=null)
        {
// check that the "-progress" function is available.
           
$parser = new FfmpegParser($config);
           
$available_commands = $parser->getCommands();
            if(isset(
$available_commands['progress']) === false)
            {
                throw new
Exception('Your version of FFmpeg cannot support the Native progress handler. Please use ProgressHandlerOutput instead.');
            }

           
parent::__construct($callback, $config);
           
           
$this->_progress_file = null;
           
$this->_input = null;
           
$this->_output = null;
        }
       
        protected function
_getRawData()
        {
            if(
is_file($this->_progress_file) === false)
            {
                return
'';
            }

// there is a problem reading from the chunking file, so we must copy and then read, then delete the copy
// in order to succesfully read the data.
           
$copy = $this->_progress_file.'.'.time().'.txt';
           
copy($this->_progress_file, $copy);
           
$data = file_get_contents($copy);
            @
unlink($copy);
            return
$data;
        }
        
        protected function
_parseOutputData(&$return_data, $raw_data)
        {
           
$return_data['started'] = true;

           
$return_data['input_count'] = count($this->_input);
           
$return_data['input_file'] = $return_data['input_count'] === 1 ? $this->_input[0] : $this->_input;

           
$return_data['output_count'] = count($this->_output);
           
$return_data['output_file'] = $return_data['output_count'] === 1 ? $this->_output[0] : $this->_output;

            if(empty(
$raw_data) === true)
            {
                if(empty(
$this->_last_probe_data) === true)
                {
                   
$return_data['status'] = self::ENCODING_STATUS_PENDING;
                }
                else
                {
                   
$return_data['percentage'] = 100;
                   
$return_data['finished'] = true;
                   
$return_data['status'] = self::ENCODING_STATUS_FINISHED;
                }
                return;
            }

           
$return_data['status'] = self::ENCODING_STATUS_ENCODING;
           
           
$return_data['process_file'] = $this->_progress_file;

// parse out the details of the data into the seperate chunks.
           
$parts = preg_split('/frame=/', $raw_data);
           
array_shift($parts);

            foreach (
$parts as $key=>$part)
            {
               
$data_parts = preg_split('/=|\r\n|\r|\n/', trim($part));
               
$data = array(
                   
'frames' => $data_parts[0],
                );
                for(
$i=1, $l=count($data_parts)-1; $i<$l; $i+=2)
                {
                   
$data[$data_parts[$i]] = $data_parts[$i+1];
                }
               
$parts[$key] = $data;
            }

           
$ended = false;
            if(empty(
$parts) === false)
            {
               
$last_key = count($parts)-1;

               
$return_data['frame'] = $parts[$last_key]['frames'];
               
$return_data['fps'] = $parts[$last_key]['fps'];
               
$return_data['size'] = $parts[$last_key]['total_size'];
               
$return_data['duration'] = new Timecode($parts[$last_key]['out_time'], Timecode::INPUT_FORMAT_TIMECODE);
               
$return_data['percentage'] = ($return_data['duration']->total_seconds/$this->_total_duration->total_seconds)*100;
               
$return_data['dup'] = $parts[$last_key]['dup_frames'];
               
$return_data['drop'] = $parts[$last_key]['drop_frames'];
                   
                if(
$parts[$last_key]['progress'] === 'end')
                {
                   
$ended = true;
                   
$return_data['finished'] = true;
                    if(
$return_data['percentage'] < 99.5)
                    {
                       
$return_data['interrupted'] = true;
                       
$return_data['status'] = self::ENCODING_STATUS_INTERRUPTED;
                    }
                    else
                    {
                       
$return_data['percentage'] = 100;
                    }
                }

// work out the fps average for performance reasons
               
if(count($parts) === 1)
                {
                   
$return_data['fps_avg'] = $return_data['frame']/$return_data['run_time'];
                }
                else
                {
                   
$total_fps = 0;
                    foreach (
$parts as $part)
                    {
                       
$total_fps += $part['fps'];
                    }
                   
$return_data['fps_avg'] = $total_fps/($last_key+1);
                }
            }

            if(
$ended === true)
            {
               
$this->_deleteProgressFile();

               
$return_data['finished'] = true;
                if(
$return_data['status'] !== self::ENCODING_STATUS_INTERRUPTED)
                {
                   
$return_data['completed'] = true;
                   
$return_data['status'] = self::ENCODING_STATUS_FINISHED;
                }
            }
            else if(
$return_data['percentage'] === 100)
            {
               
$return_data['completed'] = true;
               
$return_data['status'] = self::ENCODING_STATUS_COMPLETED;
            }
            else if(
$return_data['percentage'] >= 99.5)
            {
               
$return_data['percentage'] = 100;
               
$return_data['status'] = self::ENCODING_STATUS_FINALISING;
            }

           
$this->_last_probe_data = $return_data;
        }

        protected function
_deleteProgressFile()
        {
            @
unlink($this->_progress_file);
        }
        
        public function
attachFfmpegProcess(FfmpegProcess $process, Config $config=null)
        {
           
parent::attachFfmpegProcess($process, $config);

           
$this->_progress_file = tempnam($this->_config->temp_directory, 'phpvideotoolkit_progress_'.time().'_');
           
$this->_input = $this->_ffmpeg_process->getAllInput();
           
$this->_output = $this->_ffmpeg_process->getAllOutput();
           
$this->_ffmpeg_process->addCommand('-progress', $this->_progress_file);
        }
     }