| Current File : /home/jvzmxxx/wiki/extensions/TimedMediaHandler/handlers/OggHandler/OggHandler.php |
<?php
/**
* ogg handler
*/
class OggHandlerTMH extends TimedMediaHandler {
const METADATA_VERSION = 2;
/**
* @param $image File
* @param $path string
* @return string
*/
function getMetadata( $image, $path ) {
$metadata = [ 'version' => self::METADATA_VERSION ];
try {
$f = new File_Ogg( $path );
$streams = [];
foreach ( $f->listStreams() as $streamIDs ) {
foreach ( $streamIDs as $streamID ) {
$stream = $f->getStream( $streamID );
$streams[$streamID] = [
'serial' => $stream->getSerial(),
'group' => $stream->getGroup(),
'type' => $stream->getType(),
'vendor' => $stream->getVendor(),
'length' => $stream->getLength(),
'size' => $stream->getSize(),
'header' => $stream->getHeader(),
'comments' => $stream->getComments()
];
}
}
$metadata['streams'] = $streams;
$metadata['length'] = $f->getLength();
// Get the offset of the file (in cases where the file is a segment copy)
$metadata['offset'] = $f->getStartOffset();
} catch ( OggException $e ) {
// File not found, invalid stream, etc.
$metadata['error'] = [
'message' => $e->getMessage(),
'code' => $e->getCode()
];
}
return serialize( $metadata );
}
/**
* Display metadata box on file description page.
*
* This is pretty basic, it puts data from all the streams together,
* and only outputs a couple of the most commonly used ogg "comments",
* with comments from all the streams combined
*
* @param File $file
* @param bool|IContextSource $context Context to use (optional)
* @return array|bool
*/
public function formatMetadata( $file, $context = false ) {
$meta = $this->getCommonMetaArray( $file );
if ( count( $meta ) === 0 ) {
return false;
}
return $this->formatMetadataHelper( $meta, $context );
}
/**
* Get some basic metadata properties that are common across file types.
*
* @param File $file
* @return array Array of metadata. See MW's FormatMetadata class for format.
*/
public function getCommonMetaArray( File $file ) {
$metadata = $this->unpackMetadata( $file->getMetadata() );
if ( !$metadata || isset( $metadata['error'] ) || !isset( $metadata['streams'] ) ) {
return [];
}
// See http://www.xiph.org/vorbis/doc/v-comment.html
// http://age.hobba.nl/audio/mirroredpages/ogg-tagging.html
$metadataMap = [
'title' => 'ObjectName',
'artist' => 'Artist',
'performer' => 'Artist',
'description' => 'ImageDescription',
'license' => 'UsageTerms',
'copyright' => 'Copyright',
'organization' => 'dc-publisher',
'date' => 'DateTimeDigitized',
'location' => 'LocationDest',
'contact' => 'Contact',
'encoded_using' => 'Software',
'encoder' => 'Software',
// OpenSubtitles.org hash. Identifies source video.
'source_ohash' => 'OriginalDocumentID',
'comment' => 'UserComment',
'language' => 'LanguageCode',
];
$props = [];
foreach ( $metadata['streams'] as $stream ) {
if ( isset( $stream['vendor'] ) ) {
if ( !isset( $props['Software'] ) ) {
$props['Software'] = [];
}
$props['Software'][] = trim( $stream['vendor'] );
}
if ( !isset( $stream['comments'] ) ) {
continue;
}
foreach ( $stream['comments'] as $name => $rawValue ) {
// $value will be an array if the file has
// a multiple tags with the same name. Otherwise it
// is a string.
foreach ( (array) $rawValue as $value ) {
$trimmedValue = trim( $value );
if ( $trimmedValue === '' ) {
continue;
}
$lowerName = strtolower( $name );
if ( isset( $metadataMap[$lowerName] ) ) {
$convertedName = $metadataMap[$lowerName];
if ( !isset( $props[$convertedName] ) ) {
$props[$convertedName] = [];
}
$props[$convertedName][] = $trimmedValue;
}
}
}
}
// properties might be duplicated across streams
foreach ( $props as &$type ) {
$type = array_unique( $type );
$type = array_values( $type );
}
return $props;
}
/**
* Get the "media size"
*
* @param $file File
* @param $path string
* @param $metadata bool
* @return array|bool
*/
function getImageSize( $file, $path, $metadata = false ) {
global $wgMediaVideoTypes;
// Just return the size of the first video stream
if ( $metadata === false ) {
$metadata = $file->getMetadata();
}
$metadata = $this->unpackMetadata( $metadata );
if ( isset( $metadata['error'] ) || !isset( $metadata['streams'] ) ) {
return false;
}
foreach ( $metadata['streams'] as $stream ) {
if ( in_array( $stream['type'], $wgMediaVideoTypes ) ) {
$pictureWidth = $stream['header']['PICW'];
$parNumerator = $stream['header']['PARN'];
$parDenominator = $stream['header']['PARD'];
if ( $parNumerator && $parDenominator ) {
// Compensate for non-square pixel aspect ratios
$pictureWidth = $pictureWidth * $parNumerator / $parDenominator;
}
return [
intval( $pictureWidth ),
intval( $stream['header']['PICH'] )
];
}
}
return [ false, false ];
}
/**
* @param $metadata
* @return bool|mixed
*/
function unpackMetadata( $metadata ) {
wfSuppressWarnings();
$unser = unserialize( $metadata );
wfRestoreWarnings();
if ( isset( $unser['version'] ) && $unser['version'] == self::METADATA_VERSION ) {
return $unser;
} else {
return false;
}
}
/**
* @param $image
* @return string
*/
function getMetadataType( $image ) {
return 'ogg';
}
/**
* @param $file File
*/
function getWebType( $file ) {
$baseType = ( $file->getWidth() == 0 && $file->getHeight() == 0 )? 'audio' : 'video';
$baseType .= '/ogg';
$streamTypes = $this->getStreamTypes( $file );
if ( !$streamTypes ) {
return $baseType;
}
$codecs = strtolower( implode( ", ", $streamTypes ) );
return $baseType . '; codecs="' . $codecs . '"';
}
/**
* @param $file File
* @return array|bool
*/
function getStreamTypes( $file ) {
$streamTypes = [];
$metadata = $this->unpackMetadata( $file->getMetadata() );
if ( !$metadata || isset( $metadata['error'] ) ) {
return false;
}
foreach ( $metadata['streams'] as $stream ) {
$streamTypes[] = $stream['type'];
}
return array_unique( $streamTypes );
}
/**
* @param $file File
* @return int
*/
function getOffset( $file ) {
$metadata = $this->unpackMetadata( $file->getMetadata() );
if ( !$metadata || isset( $metadata['error'] ) || !isset( $metadata['offset'] ) ) {
return 0;
} else {
return $metadata['offset'];
}
}
/**
* @param $file File
* @return int
*/
function getLength( $file ) {
$metadata = $this->unpackMetadata( $file->getMetadata() );
if ( !$metadata || isset( $metadata['error'] ) ) {
return 0;
} else {
return $metadata['length'];
}
}
/**
* Get useful response headers for GET/HEAD requests for a file with the given metadata
* @param $metadata mixed Result this handlers getMetadata() for a file
* @return Array
*/
public function getStreamHeaders( $metadata ) {
$metadata = $this->unpackMetadata( $metadata );
if ( $metadata && !isset( $metadata['error'] ) && isset( $metadata['length'] ) ) {
return [ 'X-Content-Duration' => floatval( $metadata[ 'length' ] ) ];
}
return [];
}
/**
* @param $file File
* @return float|int
*/
function getFramerate( $file ) {
$metadata = $this->unpackMetadata( $file->getMetadata() );
if ( !$metadata || isset( $metadata['error'] ) ) {
return 0;
} else {
// Return the first found theora stream framerate:
foreach ( $metadata['streams'] as $stream ) {
if ( $stream['type'] == 'Theora' ){
return $stream['header']['FRN'] / $stream['header']['FRD'];
}
}
return 0;
}
}
/**
* @param $file File
* @return String
*/
function getShortDesc( $file ) {
global $wgLang, $wgMediaAudioTypes, $wgMediaVideoTypes;
$streamTypes = $this->getStreamTypes( $file );
if ( !$streamTypes ) {
return parent::getShortDesc( $file );
}
if ( array_intersect( $streamTypes, $wgMediaVideoTypes ) ) {
// Count multiplexed audio/video as video for short descriptions
$msg = 'timedmedia-ogg-short-video';
} elseif ( array_intersect( $streamTypes, $wgMediaAudioTypes ) ) {
$msg = 'timedmedia-ogg-short-audio';
} else {
$msg = 'timedmedia-ogg-short-general';
}
return wfMessage( $msg, implode( '/', $streamTypes ),
$wgLang->formatTimePeriod( $this->getLength( $file ) ) )->text();
}
/**
* @param $file File
* @return String
*/
function getLongDesc( $file ) {
global $wgLang, $wgMediaVideoTypes, $wgMediaAudioTypes;
$streamTypes = $this->getStreamTypes( $file );
if ( !$streamTypes ) {
$unpacked = $this->unpackMetadata( $file->getMetadata() );
if ( isset( $unpacked['error']['message'] ) ) {
return wfMessage( 'timedmedia-ogg-long-error', $unpacked['error']['message'] )->text();
} else {
return wfMessage( 'timedmedia-ogg-long-no-streams' )->text();
}
}
if ( array_intersect( $streamTypes, $wgMediaVideoTypes ) ) {
if ( array_intersect( $streamTypes, $wgMediaAudioTypes ) ) {
$msg = 'timedmedia-ogg-long-multiplexed';
} else {
$msg = 'timedmedia-ogg-long-video';
}
} elseif ( array_intersect( $streamTypes, $wgMediaAudioTypes ) ) {
$msg = 'timedmedia-ogg-long-audio';
} else {
$msg = 'timedmedia-ogg-long-general';
}
$size = 0;
$unpacked = $this->unpackMetadata( $file->getMetadata() );
if ( !$unpacked || isset( $metadata['error'] ) ) {
$length = 0;
} else {
$length = $this->getLength( $file );
foreach ( $unpacked['streams'] as $stream ) {
if ( isset( $stream['size'] ) ) {
$size += $stream['size'];
}
}
}
return wfMessage(
$msg,
implode( '/', $streamTypes ),
$wgLang->formatTimePeriod( $length ),
$wgLang->formatBitrate( $this->getBitRate( $file ) )
)->numParams(
$file->getWidth(),
$file->getHeight()
)->text();
}
/**
* @param $file File
* @return float|int
*/
function getBitRate( $file ) {
$size = 0;
$unpacked = $this->unpackMetadata( $file->getMetadata() );
if ( !$unpacked || isset( $unpacked['error'] ) ) {
$length = 0;
} else {
$length = $this->getLength( $file );
if ( isset( $unpacked['streams'] ) ) {
foreach ( $unpacked['streams'] as $stream ) {
if ( isset( $stream['size'] ) ) {
$size += $stream['size'];
}
}
}
}
return $length == 0 ? 0 : $size / $length * 8;
}
}