~jstys-z/helioviewer.org/client5

« back to all changes in this revision

Viewing changes to src/php/Movie/FFMPEGEncoder.php

  • Committer: Keith Hughitt
  • Date: 2012-06-04 17:27:01 UTC
  • Revision ID: keith.hughitt@nasa.gov-20120604172701-eo2sj3ylxh4bik4l
Added support for reconnecting to MySQL if the connection fails when querying the db to determine which files are new

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<?php
2
 
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
 
/**
4
 
 * Movie_FFMPEGEncoder Class Definition
5
 
 * 
6
 
 * Detecting problems with FFmpeg encoding:
7
 
 *  When using exec to call FFmpeg from the command line no useful return code or output
8
 
 *  information is returned. In order to the detect problems then the simplest way is to
9
 
 *  check and make sure the filesize is reasonable.
10
 
 *
11
 
 *
12
 
 * PHP version 5
13
 
 *
14
 
 * @category Movie
15
 
 * @package  Helioviewer
16
 
 * @author   Jaclyn Beck <jaclyn.r.beck@gmail.com>
17
 
 * @author   Keith Hughitt <keith.hughitt@nasa.gov>
18
 
 * @license  http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
19
 
 * @link     http://launchpad.net/helioviewer.org
20
 
 */
21
 
/**
22
 
 * Calls FFMpeg commands
23
 
 *
24
 
 * @category Movie
25
 
 * @package  Helioviewer
26
 
 * @author   Jaclyn Beck <jaclyn.r.beck@gmail.com>
27
 
 * @author   Keith Hughitt <keith.hughitt@nasa.gov>
28
 
 * @license  http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
29
 
 * @link     http://launchpad.net/helioviewer.org
30
 
 */
31
 
class Movie_FFMPEGEncoder
32
 
{
33
 
    
34
 
    private $_directory;
35
 
    private $_filename;
36
 
    private $_format;
37
 
    private $_frameRate;
38
 
    private $_width;
39
 
    private $_height;
40
 
    private $_title;
41
 
    private $_description;
42
 
    private $_comment;    
43
 
    
44
 
    /**
45
 
     * Constructor
46
 
     * 
47
 
     * @param {int} $frameRate The number of frames per second in the movie
48
 
     * 
49
 
     * @return void
50
 
     */
51
 
    public function __construct($directory, $filename, $frameRate, $width, $height, $title, $description, $comment)
52
 
    {
53
 
        $info = pathinfo($filename);
54
 
        
55
 
        $this->_directory   = $directory;
56
 
        $this->_filename    = $filename;
57
 
        $this->_frameRate   = $frameRate;
58
 
        $this->_width       = $width;
59
 
        $this->_height      = $height;
60
 
        $this->_title       = $title;
61
 
        $this->_description = $description;
62
 
        $this->_comment     = $comment;
63
 
        $this->_format      = $info['extension'];
64
 
        
65
 
        $this->_log = fopen($directory . 'ffmpeg.log', 'a');
66
 
    }
67
 
    
68
 
    /**
69
 
     * Creates a medium quality video
70
 
     */
71
 
    public function createVideo()
72
 
    {
73
 
        $outputFile = $this->_directory . $this->_filename;
74
 
 
75
 
        if ($this->_format == "mp4") {
76
 
            $this->_createH264Video($outputFile);
77
 
        } else if ($this->_format == "webm") {
78
 
            $this->_createWebMVideo($outputFile);
79
 
        }
80
 
        
81
 
        // If FFmpeg segfaults, an empty movie container may still be produced,
82
 
        if (!file_exists($outputFile) || filesize($outputFile) < 1000)
83
 
            throw new Exception("FFmpeg error encountered.", 43);
84
 
 
85
 
        return $outputFile;
86
 
    }
87
 
    
88
 
    /**
89
 
     * Creates a high quality video
90
 
     */
91
 
    public function createHQVideo()
92
 
    {
93
 
        $baseFilename = substr($this->_filename, 0, -strlen($this->_format) - 1);
94
 
        $outputFile = sprintf("%s%s-hq.%s", $this->_directory, $baseFilename, $this->_format);
95
 
        
96
 
        if ($this->_format == "mp4") {
97
 
            $this->_createH264Video($outputFile, HV_X264_HQ_PRESET, 15);
98
 
        } else if ($this->_format == "webm") {
99
 
            $this->_createWebMVideo($outputFile, 1);
100
 
        }
101
 
        
102
 
        // If FFmpeg segfaults, an empty movie container may still be produced
103
 
        if (!file_exists($outputFile) || filesize($outputFile) < 1000)
104
 
            throw new Exception("FFmpeg error encountered.", 43);
105
 
 
106
 
        return $outputFile;
107
 
    }
108
 
    
109
 
    /**
110
 
     * Creates a WebM/VP8 video
111
 
     */
112
 
    private function _createWebMVideo($outputFile, $qmax=40)
113
 
    {
114
 
        //$cmd = HV_FFMPEG . " -r " . $this->_frameRate . " -i " . $this->_directory . "/frames/frame%d.bmp"
115
 
        //    . " -r " . $this->_frameRate . " -f webm -vcodec libvpx -qmax $qmax -threads " . HV_FFMPEG_MAX_THREADS 
116
 
        //    . " -s " . $this->_width . "x" . $this->_height . " -an -y $outputFile";
117
 
        $cmd = sprintf(
118
 
            "%s -r %f -i %sframes/frame%%d.bmp -r %f -f webm -vcodec libvpx -qmin 1 -qmax %d %s -threads %d -s %dx%d -an -y %s 2>/dev/null",
119
 
            HV_FFMPEG,
120
 
            $this->_frameRate,
121
 
            $this->_directory,
122
 
            $this->_frameRate,
123
 
            $qmax,
124
 
            $this->_getMetaDataString(),
125
 
            HV_FFMPEG_MAX_THREADS,
126
 
            $this->_width,
127
 
            $this->_height,
128
 
            $outputFile
129
 
        );
130
 
        
131
 
        $this->_logCommand($cmd);
132
 
 
133
 
        // Run FFmpeg        
134
 
        $output = shell_exec($cmd);
135
 
    }
136
 
    
137
 
    /**
138
 
     * Creates a video in whatever format is given in $filename
139
 
     * 
140
 
     * NOTE: Frame rate MUST be specified twice in the command, before and after the input file, or ffmpeg will start
141
 
     *       cutting off frames to adjust for what it thinks is the right frameRate. 
142
 
     *
143
 
     * @param int    $width       the width of the video
144
 
     * @param int    $height      the height of the video
145
 
     * 
146
 
     * @return String the filename of the video
147
 
     */
148
 
    private function _createH264Video($outputFile, $preset=HV_X264_PRESET, $crf=18)
149
 
    {
150
 
        // Include x264 FFpreset if specified
151
 
        if ($preset) {
152
 
            $ffpreset = "-vpre $preset ";
153
 
        } else {
154
 
            $ffpreset = "";
155
 
        }
156
 
        $cmd = HV_FFMPEG . " -r " . $this->_frameRate . " -i " . $this->_directory . "frames/frame%d.bmp"
157
 
            . " -r " . $this->_frameRate . " -vcodec libx264 " . $ffpreset . $this->_getMetaDataString() . "-threads " 
158
 
            . HV_FFMPEG_MAX_THREADS . " -crf $crf -s " . $this->_width . "x" . $this->_height . " -an -y $outputFile 2>/dev/null";
159
 
            
160
 
        $this->_logCommand($cmd);
161
 
            
162
 
        // Run FFmpeg
163
 
        $output = shell_exec($cmd);
164
 
    }
165
 
    
166
 
    /**
167
 
     * Creates a flash video by converting it from the high quality file
168
 
     *
169
 
     * @param string $directory  The directory where both files are stored
170
 
     * @param string $filename   Base filename of the video
171
 
     * @param string $origFormat The original container format
172
 
     * @param string $newFormat  The new container format
173
 
     * 
174
 
     * @return void
175
 
     */
176
 
    public function createFlashVideo()
177
 
    {
178
 
        $file = $this->_directory . substr($this->_filename, 0, -4);
179
 
        
180
 
        $cmd = sprintf("%s -i %s.mp4 -vcodec copy %s -threads %d %s.flv 2>/dev/null",
181
 
            HV_FFMPEG,
182
 
            $file,
183
 
            $this->_getMetaDataString(),
184
 
            HV_FFMPEG_MAX_THREADS,
185
 
            $file
186
 
        );
187
 
 
188
 
        $this->_logCommand($cmd);
189
 
        exec($cmd);
190
 
 
191
 
        // Check to ensure that movie size is valid
192
 
        if (filesize($file . ".flv") < 1000)
193
 
            throw new Exception("FFmpeg error encountered: Unable to create flv.", 43);
194
 
    }
195
 
    
196
 
    
197
 
    /**
198
 
     * Creates an ipod-compatible mp4 video
199
 
 
200
 
     * @param int    $width      The width of the video
201
 
     * @param int    $height     The height of the video
202
 
     * 
203
 
     * @return String the filename of the ipod video
204
 
     */
205
 
    public function createIpodVideo($format, $width, $height) 
206
 
    {
207
 
        $ipodVideoName = $this->_directory . "/ipod-" . $this->_filename . "." . $format;
208
 
        
209
 
        $macFlags = "-flags +loop -cmp +chroma -vcodec libx264 -me_method 'hex' -me_range 16 "
210
 
                  . "-keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 10 "
211
 
                  . "-qmax 51 -qdiff 4 -bf 3 -directpred 1 -trellis 1 -wpredp 2 -an -y";
212
 
        
213
 
        $cmd = HV_FFMPEG . " -i " . $this->_directory . "/frames/frame%d.bmp -r " . $this->_frameRate
214
 
            . " -f mp4 -b 800k -coder 0 -bt 200k -maxrate 96k -bufsize 96k -rc_eq 'blurCplx^(1-qComp)' -level 30 "
215
 
            . "-refs 1 -subq 5 -g 30 -s " . $width . "x" . $height . " $macFlags $ipodVideoName";
216
 
            
217
 
        exec($cmd);
218
 
 
219
 
        // Check to ensure that movie size is valid
220
 
        if (filesize($ipodVideoName) < 1000)
221
 
            throw new Exception("FFmpeg error encountered: Unable to create iPod video.", 43);
222
 
 
223
 
        return $ipodVideoName;
224
 
    }
225
 
    
226
 
    /**
227
 
     * Adjusts the movie format that is used when encoding videos
228
 
     * 
229
 
     * @param {string} $format Extension for the format to switch to
230
 
     * 
231
 
     * @return void
232
 
     */
233
 
    public function setFormat($format) {
234
 
        $this->_format = $format;
235
 
        $this->_filename = str_replace(array("webm", "mp4"), $format, 
236
 
                            $this->_filename);
237
 
    }
238
 
 
239
 
    /**    
240
 
     * Log FFmpeg command
241
 
     */
242
 
    private function _logCommand($cmd)
243
 
    {
244
 
        $message = "========================================================\n" 
245
 
                 . "$cmd\n";
246
 
        fwrite($this->_log, $message);
247
 
    }
248
 
    
249
 
    /**
250
 
     * Creates the portion of the ffmpeg command relating to metadata properties
251
 
     */
252
 
    private function _getMetaDataString()
253
 
    {
254
 
        return sprintf(
255
 
            '-metadata title="%s" -metadata artist="Helioviewer.org" ' . 
256
 
            '-metadata description="%s" -metadata comment="%s" -timestamp "%s" ',
257
 
            $this->_title,
258
 
            $this->_description,
259
 
            str_replace(array("mp4", "webm"), $this->_format, $this->_comment),
260
 
            date("Y-m-d\TH:i:s\Z")
261
 
        );
262
 
    }
263
 
}
264
 
?>