* @version $Revision: 18154 $ * @static */ class FfmpegToolkitHelper { /** * Figure out what operations and properties are supported by the * FfmpegToolkit and return them. * * @return GalleryStatus a status code * array('operations' => ..., 'properties' => ...) */ function getOperationsAndProperties() { global $gallery; list ($ret, $ffmpegPath) = GalleryCoreApi::getPluginParameter('module', 'ffmpeg', 'path'); if ($ret) { return array($ret, null); } if (empty($ffmpegPath)) { return array(GalleryCoreApi::error(ERROR_MISSING_VALUE), null); } list ($ret, $tests, $mimeTypes, $supportsOffset, $mimeTypesEncoder, $encoderAudioCodecs, $version) = FfmpegToolkitHelper::testBinary($ffmpegPath); if ($ret) { return array($ret, null); } /* -------------------- Operations -------------------- */ /* extract */ $operations['convert-to-image/jpeg']['params'] = array(); $operations['convert-to-image/jpeg']['description'] = $gallery->i18n('Convert to a JPEG'); $operations['convert-to-image/jpeg']['mimeTypes'] = $mimeTypes; $operations['convert-to-image/jpeg']['outputMimeType'] = 'image/jpeg'; if ($supportsOffset) { $operations['select-offset'] = array( 'params' => array(array('type' => 'float', 'description' => $gallery->i18n('offset in seconds'))), 'description' => $gallery->i18n('Select time offset in movie file'), 'mimeTypes' => $mimeTypes, 'outputMimeType' => null); } /* Convert to Flash Video */ if (in_array('video/x-flv', $mimeTypesEncoder)) { $operations['convert-to-video/x-flv']['params'] = array(); $operations['convert-to-video/x-flv']['description'] = $gallery->i18n('Convert to Flash Video'); $operations['convert-to-video/x-flv']['mimeTypes'] = $mimeTypes; $operations['convert-to-video/x-flv']['outputMimeType'] = 'video/x-flv'; /* set-video-dimensions */ $operations['set-video-dimensions']['params'] = array( array('type' => 'int', 'description' => $gallery->i18n('video width in pixels')), array('type' => 'int', 'description' => $gallery->i18n('video height in pixels'))); $operations['set-video-dimensions']['description'] = $gallery->i18n('Set video dimensions'); $operations['set-video-dimensions']['mimeTypes'] = $mimeTypes; $operations['set-video-dimensions']['outputMimeType'] = null; /* set-video-framerate */ $operations['set-video-framerate']['params'] = array( array('type' => 'float', 'description' => $gallery->i18n( 'frames per second'))); $operations['set-video-framerate']['description'] = $gallery->i18n( 'Set video frames per second property'); $operations['set-video-framerate']['mimeTypes'] = $mimeTypes; $operations['set-video-framerate']['outputMimeType'] = null; $operations['set-video-sameq']['params'] = array(); $operations['set-video-sameq']['description'] = $gallery->i18n('Set same video quality'); $operations['set-video-sameq']['mimeTypes'] = $mimeTypes; $operations['set-video-sameq']['outputMimeType'] = null; /* If mp3 audio supported */ if (in_array('mp3', $encoderAudioCodecs)) { /* set-audio-channels */ $operations['set-audio-channels']['params'] = array( array('type' => 'int', 'description' => $gallery->i18n( 'number of channels'))); $operations['set-audio-channels']['description'] = $gallery->i18n( 'Set audio channels property'); $operations['set-audio-channels']['mimeTypes'] = $mimeTypes; $operations['set-audio-channels']['outputMimeType'] = null; /* set-audio-samplerate */ $operations['set-audio-samplerate']['params'] = array( array('type' => 'int', 'description' => $gallery->i18n( 'audio sample rate (Hz / cycles per second)'))); $operations['set-audio-samplerate']['description'] = $gallery->i18n( 'Set audio rate property'); $operations['set-audio-samplerate']['mimeTypes'] = $mimeTypes; $operations['set-audio-samplerate']['outputMimeType'] = null; } } /* -------------------- Properties -------------------- */ /* Dimensions */ $properties['dimensions']['type'] = 'int,int'; $properties['dimensions']['description'] = $gallery->i18n('Get the width and height of the movie'); $properties['dimensions']['mimeTypes'] = $mimeTypes; $properties['dimensions-and-duration']['type'] = 'int,int,float'; $properties['dimensions-and-duration']['description'] = $gallery->i18n('Get the width, height and duration of the movie'); $properties['dimensions-and-duration']['mimeTypes'] = $mimeTypes; $properties['video-framerate']['type'] = 'float'; $properties['video-framerate']['description'] = $gallery->i18n('Get video frames per seconds of the movie'); $properties['video-framerate']['mimeTypes'] = $mimeTypes; $properties['audio-samplerate']['type'] = 'int'; $properties['audio-samplerate']['description'] = $gallery->i18n('Get audio samples per seconds of the movie'); $properties['audio-samplerate']['mimeTypes'] = $mimeTypes; $properties['audio-channels']['type'] = 'int'; $properties['audio-channels']['description'] = $gallery->i18n('Get number of audio channels in movie'); $properties['audio-channels']['mimeTypes'] = $mimeTypes; return array(null, array('operations' => $operations, 'properties' => $properties)); } /** * Test if the given path has a working Ffmpeg binary. * * This is done by calling the binary with the -formats flag and * making sure it runs properly. * * @param string $ffmpegPath path to the Ffmpeg we are testing * @return array GalleryStatus general status of tests * array of array ('name' => string: the name of the binary, * 'success' => boolean: test successful? * 'results' => string: the ffmpeg output) * array hash map of mime types * boolean true if ffmpeg supports -ss time_offset * array of strings listing mime types that can be encoded * array of strings listing available audio codecs for encoding * string containing the ffmpeg version */ function testBinary($ffmpegPath) { global $gallery; $platform =& $gallery->getPlatform(); /* * If the path is not restricted by open_basedir, then verify that it's legal. * Else just hope that it's valid and use it. */ if (!$platform->isRestrictedByOpenBaseDir($ffmpegPath)) { if (!$platform->file_exists($ffmpegPath) || !$platform->is_file($ffmpegPath)) { return array(GalleryCoreApi::error(ERROR_BAD_PATH), null, null, null, null, null, null); } } else { return array(GalleryCoreApi::error(ERROR_BAD_PATH, null, null, '"' . $ffmpegPath . '" is not specified in open_basedir.'), null, null, null, null, null, null); } /* We only care about video for now */ /** @todo: Add '3g2' => '3g2', '3gp' => '3gp' when recognized as videos */ $relevantTypes = array('mpeg' => 'mpeg', 'asf' => 'asf', 'avi' => 'avi', 'mov' => 'mov', 'wmv1' => 'wmv', 'flv' => 'flv', 'mp4' => 'mp4'); /* We only care about encoding flash video for now */ $relevantEncode = array('flv' => 'flv'); /** * @todo: Add 'adpcm_swf' => 'adpcm_swf' to relevantAudioCodecs if/when videos play * correctly */ $relevantAudioCodecs = array('mp3' => 'mp3', 'libmp3lame' => 'mp3'); list ($ignored, $results) = $platform->exec(array(array($ffmpegPath, '-formats'))); $version = array(); list ($ignored, $ignored, $version) = $platform->exec(array(array($ffmpegPath, '-version'))); $mimeTypes = array(); $mimeTypesEncoder = array(); $encoderAudioCodecs = array(); $success = false; $i = 0; while ($i < sizeof($results)) { $resultLine = $results[$i++]; /* * ffmpeg 0.4.6 says: * File formats: * Decoding: mpeg mpegts pgm pgmyuv ppm .Y.U.V pgmpipe pgmyuvpipe * ppmpipe mp3 ac3 m4v mpegvideo mjpeg s16le s16be u16le u16be s8 u8 mulaw alaw * rawvideo rm asf avi wav swf au mov jpeg dv ffm video_grab_device * audio_device rtsp redir sdp rtp * [multiple lines] * Codecs: * .... * * ffmpeg 0.4.7 says: * Input audio/video file formats: mpeg mpegts image ... * [all on one line] * * ffmpeg 0.4.8 says: * File formats: * E 3gp * D 4xm * D RoQ * DE ac3 * DE ala * DE asf * E asf * ... * Image formats: * D pnm * E pbm * E pgm * ... * Codecs: * D V 4xm * D V D 8bps * EA ac3 * DEA adpcm_4xm */ if (preg_match('|Input audio/video file formats: (.*)$|', $resultLine, $regs)) { /* We have found 0.4.7 format, read single line */ /** @todo: Support mimeTypesEncoder and encoderAudioCodecs */ foreach (explode(' ', $regs[1]) as $type) { if (isset($relevantTypes[$type])) { list ($ret, $mime) = GalleryCoreApi::convertExtensionToMime($relevantTypes[$type]); if ($ret) { return array($ret, null, null, null, null, null, null); } $mimeTypes[$mime] = 1; } } $success = true; } else if (preg_match('/ Decod(?:ing|ers): (.*)$/', $resultLine, $regs)) { /* We have found 0.4.6 format, read until Codec: line */ /** @todo: Support mimeTypesEncoder and encoderAudioCodecs */ do { foreach (explode(' ', $regs[1]) as $type) { if (isset($relevantTypes[$type])) { list ($ret, $mime) = GalleryCoreApi::convertExtensionToMime( $relevantTypes[$type]); if ($ret) { return array($ret, null, null, null, null, null, null); } $mimeTypes[$mime] = 1; } } $resultLine = $results[$i++]; } while ($i < sizeof($results) && !preg_match('|Codecs:|', $resultLine)); $success = true; } else if (preg_match('/(File formats|Codecs):/', $resultLine, $regs)) { $resultLine = $results[$i++]; if (preg_match('/^ \w+: /', $resultLine)) { /* We have found 0.4.6 format */ continue; } if (!strcmp('File formats', $regs[1])) { /* Parse File formats */ do { list ($capabilities, $types) = preg_split('/\s+/', $resultLine, -1, PREG_SPLIT_NO_EMPTY); foreach (explode(',', $types) as $type) { if (isset($relevantTypes[$type])) { list ($ret, $mime) = GalleryCoreApi::convertExtensionToMime( $relevantTypes[$type]); if ($ret) { return array($ret, null, null, null, null, null, null); } if (preg_match('|D|', $capabilities)) { $mimeTypes[$mime] = 1; } if (isset($relevantEncode[$type]) && preg_match('|E|', $capabilities)) { $mimeTypesEncoder[$mime] = 1; } } } $resultLine = $results[$i++]; } while (!empty($resultLine)); $success = true; } else { /* Parse codecs */ do { $type = substr($resultLine, 8); $decode = ('D' == substr($resultLine, 1, 1)); $encode = ('E' == substr($resultLine, 2, 1)); $audio = ('A' == substr($resultLine, 3, 1)); $video = ('V' == substr($resultLine, 3, 1)); if (isset($relevantAudioCodecs[$type]) && $encode && $audio) { $encoderAudioCodecs[$relevantAudioCodecs[$type]] = 1; } /* Check relevant types too since wmv uses an asf container */ if (isset($relevantTypes[$type]) && $decode && $video) { list ($ret, $mime) = GalleryCoreApi::convertExtensionToMime( $relevantTypes[$type]); if ($ret) { return array($ret, null, null, null, null, null, null); } $mimeTypes[$mime] = 1; } $resultLine = $results[$i++]; } while (!empty($resultLine)); } } } $tests[] = array('name' => 'ffmpeg', 'success' => $success, 'results' => $results); /* Test if this ffmpeg supports -ss flag.. */ $supportsOffset = false; list ($ok, $flags) = $platform->exec(array(array($ffmpegPath, '-h'))); foreach ($flags as $line) { if (!strncmp($line, '-ss ', 4)) { $supportsOffset = true; break; } } return array(null, $tests, array_keys($mimeTypes), $supportsOffset, array_keys($mimeTypesEncoder), array_keys($encoderAudioCodecs), $version); } } ?>