2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
* Movie_FFMPEGEncoder Class Definition
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.
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
22
* Calls FFMpeg commands
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
31
class Movie_FFMPEGEncoder
41
private $_description;
47
* @param {int} $frameRate The number of frames per second in the movie
51
public function __construct($directory, $filename, $frameRate, $width, $height, $title, $description, $comment)
53
$info = pathinfo($filename);
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'];
65
$this->_log = fopen($directory . 'ffmpeg.log', 'a');
69
* Creates a medium quality video
71
public function createVideo()
73
$outputFile = $this->_directory . $this->_filename;
75
if ($this->_format == "mp4") {
76
$this->_createH264Video($outputFile);
77
} else if ($this->_format == "webm") {
78
$this->_createWebMVideo($outputFile);
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);
89
* Creates a high quality video
91
public function createHQVideo()
93
$baseFilename = substr($this->_filename, 0, -strlen($this->_format) - 1);
94
$outputFile = sprintf("%s%s-hq.%s", $this->_directory, $baseFilename, $this->_format);
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);
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);
110
* Creates a WebM/VP8 video
112
private function _createWebMVideo($outputFile, $qmax=40)
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";
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",
124
$this->_getMetaDataString(),
125
HV_FFMPEG_MAX_THREADS,
131
$this->_logCommand($cmd);
134
$output = shell_exec($cmd);
138
* Creates a video in whatever format is given in $filename
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.
143
* @param int $width the width of the video
144
* @param int $height the height of the video
146
* @return String the filename of the video
148
private function _createH264Video($outputFile, $preset=HV_X264_PRESET, $crf=18)
150
// Include x264 FFpreset if specified
152
$ffpreset = "-vpre $preset ";
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";
160
$this->_logCommand($cmd);
163
$output = shell_exec($cmd);
167
* Creates a flash video by converting it from the high quality file
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
176
public function createFlashVideo()
178
$file = $this->_directory . substr($this->_filename, 0, -4);
180
$cmd = sprintf("%s -i %s.mp4 -vcodec copy %s -threads %d %s.flv 2>/dev/null",
183
$this->_getMetaDataString(),
184
HV_FFMPEG_MAX_THREADS,
188
$this->_logCommand($cmd);
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);
198
* Creates an ipod-compatible mp4 video
200
* @param int $width The width of the video
201
* @param int $height The height of the video
203
* @return String the filename of the ipod video
205
public function createIpodVideo($format, $width, $height)
207
$ipodVideoName = $this->_directory . "/ipod-" . $this->_filename . "." . $format;
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";
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";
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);
223
return $ipodVideoName;
227
* Adjusts the movie format that is used when encoding videos
229
* @param {string} $format Extension for the format to switch to
233
public function setFormat($format) {
234
$this->_format = $format;
235
$this->_filename = str_replace(array("webm", "mp4"), $format,
242
private function _logCommand($cmd)
244
$message = "========================================================\n"
246
fwrite($this->_log, $message);
250
* Creates the portion of the ffmpeg command relating to metadata properties
252
private function _getMetaDataString()
255
'-metadata title="%s" -metadata artist="Helioviewer.org" ' .
256
'-metadata description="%s" -metadata comment="%s" -timestamp "%s" ',
259
str_replace(array("mp4", "webm"), $this->_format, $this->_comment),
260
date("Y-m-d\TH:i:s\Z")