<?php

/**
 * Tt_video_converter class
 *
 * @Description    Convert video in 720p and 1080p resolution
 *                 based on input video resolution
 * @Developed By   Md Mashqur Ul Alam
 * @Start Date     21-05-17
 * @return         string
 * @status         Available
 */
class Tt_video_converter {

    /**
     * Input file name from input file detail
     *
     * @var string
     */
    private $input_file_name;

    /**
     * Input file extension from input file detail
     *
     * @var string
     */
    private $input_file_ext;

    /**
     * Input file full directory location path
     *
     * @var string
     */
    private $input_file_path;

    /**
     * Input file directory location
     *
     * @var string
     */
    private $input_file_directory_path;

    /**
     * conversion formats(resolution) based on input file
     *
     * @var array
     */
    Private $output_resolutions;

    /**
     * Detail video info of input video file
     *
     * @var array
     */
    private $input_video_info;

    /**
     * Detail video info of output video file after conversion
     *
     * @var array
     */
    private $converted_video_info;

    /**
     * temporary text file directory location for keeping video information
     * Automatically deleted after encoding info into JSON format
     *
     * @var string
     */
    private $temp_file; //temporary text file for keeping video information

    /**
     * Error Messages for the error occurred at various stage of conversion
     *
     * @var array
     */
    private $error_message;

    /**
     * directory location path of the converted file
     *
     * @var array
     */
    private $output_file_path;

    /**
     * contains the directory location path of converted files
     *
     * @var array
     */
    private $converted_files_path;

    /**
     * contains the converted files name only
     *
     * @var array
     */
    private $converted_files_name;
    
    
    /**
     * contains the converted files name only
     *
     * @var array
     */
    private $result;

    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17  
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : sets different required properties for the class from input file detail 
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Parameter           : $input_file
     * @Return              : own class object   
     * @value               : $this->input_file_name is used for set video file name
                              $this->input_file_ext is used for set video file extension
                              $this->input_file_path is used for set video file path
                              $this->input_file_directory_path is used for set video file path
     * @Status              : Available
     * @version             : v2.1       
    * */
    public function set_file($input_file) {
        $this->input_file_name = $input_file['file_name'];
        $this->input_file_ext = $input_file['file_ext'];
        $this->input_file_path = $input_file['full_path'];
        $this->input_file_directory_path = $input_file['file_path'];
        return $this;
    }
    
    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17  
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : assigns value to the required properties before converting 
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Function            : set_temporary_info_file_path() is used for sets path for temporary text file which is used for saving video info temporarily 
     *                          get_video_information() is used for get input video information
     *                          check_input_video_format() is used for check video probe score for right formate check
     *                          set_output_file_resolution() is used for set output video file resulation which video is inputed
     * @Used in             : convert_video()
     * @Parameter           : null
     * @Return              : own class object   
     * @value               : null
     * @Status              : Available
     * @version             : v2.1       
    * */
    private function initialize_converter() {
        $this->set_temporary_info_file_path()
                ->get_video_information()
                ->check_input_video_format()
                ->set_output_file_resolution();
        return $this;
    }

    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17  
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : sets path for temporary text file which is used for saving video info temporarily 
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Used in             : initialize_converter()
     * @Parameter           : null
     * @Return              : own class object   
     * @value               : null
     * @Status              : Available
     * @version             : v2.1       
    * */
    private function set_temporary_info_file_path() {
        $this->temp_file = str_replace($this->input_file_ext, '.txt', $this->input_file_path);
        return $this;
    }

    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17  
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : get video file detail information using ffprobe
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Used in             : initialize_converter(), check_converted_video()
     * @Parameter           : $input_file[optional], $resolution[optional]
     * @Return              : own class object   
     * @value               : $file_path is used for keep input file path
     *                          $command is used for set Shell command
     *                          $output_info is used for keep input file information
     * @Status              : Available
     * @version             : v2.1       
    * */
    private function get_video_information($input_file = TRUE, $resolution = '') {
        $file_path = ($input_file) ? $this->input_file_path : $this->output_file_path;
        $command = '/usr/local/bin/ffprobe -i ' . $this->input_file_path . ' -v quiet -print_format json -show_format -show_streams > ' . $this->temp_file . ' 2>&1';
        //$command = 'ffprobe -i ' . $file_path . ' -v quiet -print_format json -show_format -show_streams > ' . $this->temp_file . ' 2>&1';
        exec($command, $output, $status);
        if (($status == 0) && file_exists($this->temp_file)) {
            $output_info = json_decode(file_get_contents($this->temp_file));
            unlink($this->temp_file);
        } else {
            $output_info = $output;
        }

        if ($input_file === TRUE) {
            $this->input_video_info = $output_info;
        } else {
            $this->converted_video_info[$resolution] = $output_info;
        }
        return $this;
    }

    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17  
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : check ffprobe score for input video file
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Used in             : initialize_converter()
     * @Parameter           : null
     * @Return              : own class object   
     * @value               : null
     * @Status              : Available
     * @version             : v2.1       
    * */
    private function check_input_video_format() {
        if ($this->input_video_info->format->probe_score != 100) {
            $this->error_message['probe_score'] = 'Error with file format';
        }
        return $this;
    }

    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17  
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : determines the output video resolution based on input video resolution
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Used in             : initialize_converter()
     * @Parameter           : null
     * @Return              : own class object   
     * @value               : $file_resolution is used for keep the input file resulation
     *                          $this->output_resolutions is used for set output file resulation based on input file resulation
     * @Status              : Available
     * @version             : v2.1       
    * */
    private function set_output_file_resolution() {
        if(isset($this->input_video_info->format->format_name) && $this->input_video_info->format->format_name == 'flv'){
            $this->output_resolutions = array('720p', '360p','144p');
        }else{
            //$this->output_resolutions = array('1080p', '720p', '360p','144p');
            
            if(isset($this->input_video_info->streams[0]->height)){
                $file_resolution = $this->input_video_info->streams[0]->height;
            }
            if (isset($file_resolution) && $file_resolution >= 800) {
                $this->output_resolutions = array('1080p', '720p', '360p', '144p');
            } elseif (isset($file_resolution) && $file_resolution < 800 && $file_resolution >= 500) {
                $this->output_resolutions = array('720p', '360p', '144p');
            }elseif (isset($file_resolution) && $file_resolution < 500 && $file_resolution >= 144) {
                $this->output_resolutions = array('360p', '144p');
            }elseif (isset($file_resolution) && $file_resolution < 144) {
                $this->output_resolutions = array('144p');
            }else{
                $this->output_resolutions = array('720p', '360p', '144p');
            }
        }
        
        return $this;
    }

    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17  
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : start conversion of video based on resolution
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Function            : convert_to_1080p(), convert_to_720p(), convert_to_360p(), convert_to_144p() is used for convert the inputed video based on resulation
     * @Used in             : convert_video()
     * @Parameter           : null
     * @Return              : own class object   
     * @value               : null
     * @Status              : Available
     * @version             : v2.1       
    * */
    private function run_converter() {
        foreach ($this->output_resolutions as $format) {
            if ($format == '1080p') {
                $this->convert_to_1080p();
            }
            if ($format == '720p') {
                $this->convert_to_720p();
            }
            if ($format == '360p') {
                $this->convert_to_360p();
            }
            if ($format == '144p') {
                $this->convert_to_144p();
            }
        }
    }

    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17  
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : Converts video to 1080p resolution and check output
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Function            : 
     * @Used in             : run_converter()
     * @Parameter           : null
     * @Return              : own class object   
     * @value               : $this->output_file_path is used for keep output file path
     *                          $command is used for set Shell command
     * @Status              : Available
     * @version             : v2.1       
    * */
    private function convert_to_1080p() {
        $this->output_file_path = str_replace($this->input_file_ext, '_converted_1080p.mp4', $this->input_file_path);
        
        $command = 'ffmpeg -i ' . $this->input_file_path . ' -y -codec:v libx264 -profile:v high -b:v 3000k -maxrate 3000k -bufsize 2000k -vf: scale=-2:1080 -r 20 -crf 18 -pix_fmt yuv420p ' . $this->output_file_path . ' 2>&1';

        exec($command, $output, $status);
        if (($status == 0) && file_exists($this->output_file_path)) {
            $this->converted_files_path['1080p'] = $this->output_file_path;
        } else {
            $this->error_message['conversion_error_1080p'] = $output;
        }
    }

    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17  
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : Converts video to 720p resolution and check output
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Function            : check_converted_video() is used for check the converted video
     * @Used in             : run_converter()
     * @Parameter           : null
     * @Return              : own class object   
     * @value               : $this->output_file_path is used for keep output file path
     *                          $command is used for set Shell command
     * @Status              : Available
     * @version             : v2.1       
    * */
    private function convert_to_720p() {        
        $this->output_file_path = str_replace($this->input_file_ext, '_converted_720p.mp4', $this->input_file_path);
        
        $command = 'ffmpeg -i ' . $this->input_file_path . ' -y -codec:v libx264 -profile:v high -b:v 1000k -maxrate 1000k -bufsize 2000k -vf: scale=-2:720 -r 24 -crf 18 -pix_fmt yuv420p ' . $this->output_file_path . ' 2>&1';

        exec($command, $output, $status);
        if (($status == 0) && file_exists($this->output_file_path)) {
            $this->converted_files_path['720p'] = $this->output_file_path;
            $this->check_converted_video('720p');
        } else {
            $this->error_message['conversion_error_720p'] = $output;
        }
    }
    
    /**
     * @Author              : Md. Delwar Hossain   
     * @CreatedDate         : 23-07-17  
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : Converts video to 360p resolution and check output
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Function            : check_converted_video() is used for check the converted video
     * @Used in             : run_converter()
     * @Parameter           : null
     * @Return              : own class object   
     * @value               : $this->output_file_path is used for keep output file path
     *                          $command is used for set Shell command
     * @Status              : Available
     * @version             : v2.1       
    * */
    private function convert_to_360p() {        
        $this->output_file_path = str_replace($this->input_file_ext, '_converted_360p.mp4', $this->input_file_path);
        
        $command = 'ffmpeg -i ' . $this->input_file_path . ' -y -codec:v libx264 -profile:v high -b:v 250k -maxrate 250k -bufsize 500k -vf: scale=-2:360 -r 32 -crf 18 -pix_fmt yuv420p ' . $this->output_file_path . ' 2>&1';
        
        exec($command, $output, $status);
        if (($status == 0) && file_exists($this->output_file_path)) {
            $this->converted_files_path['360p'] = $this->output_file_path;
            $this->check_converted_video('360p');
        } else {
            $this->error_message['conversion_error_360p'] = $output;
        }
    }
    
    /**
     * @Author              : Md. Delwar Hossain   
     * @CreatedDate         : 23-07-17  
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : Converts video to 144p resolution and check output
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Function            : check_converted_video() is used for check the converted video
     * @Used in             : run_converter()
     * @Parameter           : null
     * @Return              : own class object   
     * @value               : $this->output_file_path is used for keep output file path
     *                          $command is used for set Shell command
     * @Status              : Available
     * @version             : v2.1       
    * */
    private function convert_to_144p() {        
        $this->output_file_path = str_replace($this->input_file_ext, '_converted_144p.mp4', $this->input_file_path);
        
        $command = 'ffmpeg -i ' . $this->input_file_path . ' -y -codec:v libx264 -profile:v high -b:v 125k -maxrate 125k -bufsize 250k -vf: scale=-2:144 -r 36 -crf 18 -pix_fmt yuv420p ' . $this->output_file_path . ' 2>&1';
        
        exec($command, $output, $status);
        if (($status == 0) && file_exists($this->output_file_path)) {
            $this->converted_files_path['144p'] = $this->output_file_path;
            $this->check_converted_video('144p');
        } else {
            $this->error_message['conversion_error_144p'] = $output;
        }
    }
    
    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17  
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : deletes the original user inputed file
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Used in             : get_converted_files_path(), get_full_report()
     * @Parameter           : null
     * @Return              : own class object   
     * @value               : null
     * @Status              : Available
     * @version             : v2.1       
    * */
    private function delete_input_file() {
        if (file_exists($this->input_file_path)) {
            unlink($this->input_file_path);
        }
    }
    
    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17   
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : Initialize and run converter
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Function            : initialize_converter() is used for initialize converter to convert video, 
     *                          run_converter() is used for start conversion of video based on resolution
     * @Parameter           : null
     * @Return              : own class object   
     * @value               : null
     * @Status              : Available
     * @version             : v2.1       
    * */
    public function convert_video() {
        $this->initialize_converter()->run_converter();
        return $this;
    }

    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17 
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : check probe score and duration after conversion
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Function            : get_video_information() is used for get video all information
     * @Used in             : convert_to_1080p(), convert_to_720p(), convert_to_360p(), convert_to_144p()
     * @Parameter           : null
     * @Return              : own class object   
     * @value               : null
     * @Status              : Available
     * @version             : v2.1       
    * */
    private function check_converted_video() {
        foreach ($this->converted_files_path as $res => $path) {
            $this->get_video_information(FALSE, $res);

            if ($this->converted_video_info[$res]->format->probe_score === 100) {
                $this->error_message['converted_probe_score_' . $res] = 'ok';
            } else {
                $this->error_message['converted_probe_score_' . $res] = 'failed';
            }

            if ($this->input_video_info->format->duration == $this->converted_video_info[$res]->format->duration) {
                $this->error_message['duration_check_' . $res] = 'ok';
            } else {
                $this->error_message['duration_check_' . $res] = 'failed';
            }
        }
        
        return $this;
    }

    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17 
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : check probe score and duration after conversion
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Function            : delete_input_file() is used for delete input video file if file exists
     * @Used in             : convert_to_1080p(), convert_to_720p(), convert_to_360p(), convert_to_144p()
     * @Parameter           : null
     * @Return              : converted files path [array] 
     * @value               : null
     * @Status              : Available
     * @version             : v2.1       
    * */
    public function get_converted_files_path() {
        $this->delete_input_file();
        if (isset($this->error_message['conversion_error_360p']) || isset($this->error_message['conversion_error_720p']) || isset($this->error_message['conversion_error_1080p'])) {
            return $this->error_message;
        }
        
        $this->result['converted_files_path'] = $this->converted_files_path;
        return $this;
    }

    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17 
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : extract only converted file name from full path
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Parameter           : null
     * @Return              : converted files name [array] 
     * @value               : null
     * @Status              : Available
     * @version             : v2.1       
    * */
    public function get_converted_files_name() {
        foreach ($this->converted_files_path as $res => $path) {
            $this->converted_files_name[$res] = str_replace($this->input_file_directory_path, '', $path);
        }
        $this->result['converted_files_name'] = $this->converted_files_name;
        return $this;
    }

    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17 
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : return all the properties of Tt_video_converter class
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Function            : delete_input_file() is used for delete input video file if file exists
     * @Parameter           : null
     * @Return              : all_properties of this class 
     * @value               : null
     * @Status              : Available
     * @version             : v2.1       
    * */
    public function get_full_report() {
        $this->delete_input_file();
        return get_object_vars($this);
    }
    
    /**
     * @Author              : Md Mashqur Ul Alam   
     * @CreatedDate         : 21-05-17 
     * @ModifiedDate        : Null
     * @ModifiedBy          : Null
     * @Route               : Null
     * @Description         : get result array based on the functions called
     * @view                : Null
     * @redirect            : Null
     * @deprecated          : No
     * @exception           : 
     * @inheritDoc          : 
     * @Function            : delete_input_file() is used for delete input video file if file exists
     * @Parameter           : null
     * @Return              : result [array] 
     * @value               : null
     * @Status              : Available
     * @version             : v2.1       
    * */
    public function get_result(){
        $this->delete_input_file();
        return $this->result;
    }

}
