160 lines
6 KiB
PHP
160 lines
6 KiB
PHP
<?php
|
|
namespace Uiharu;
|
|
|
|
use stdClass;
|
|
use Imagick;
|
|
use RuntimeException;
|
|
use Index\IO\Stream;
|
|
use Index\IO\ProcessStream;
|
|
|
|
final class FFMPEG {
|
|
public static function grabFirstVideoFrame(string $url): Stream {
|
|
return new ProcessStream(
|
|
sprintf('ffmpeg -i %s -ss 00:00:00.000 -vframes 1 -c:v png -f image2pipe -', escapeshellarg($url)),
|
|
'rb'
|
|
);
|
|
}
|
|
|
|
public static function grabFirstAudioCover(string $url): Stream {
|
|
return self::grabFirstVideoFrame($url);
|
|
/*return new ProcessStream(
|
|
sprintf('ffmpeg -i %s -an -c:v png -f image2pipe -', escapeshellarg($url)),
|
|
'rb'
|
|
);*/
|
|
}
|
|
|
|
public static function probe(string $url): ?object {
|
|
$command = sprintf(
|
|
'ffprobe -show_streams -show_format -print_format json -v quiet -i %s',
|
|
escapeshellarg($url)
|
|
);
|
|
|
|
$ffprobe = proc_open($command, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);
|
|
if(!is_resource($ffprobe))
|
|
throw new RuntimeException('Could not open ffprobe.');
|
|
|
|
try {
|
|
$stderr = trim(stream_get_contents($pipes[2]));
|
|
if(!empty($stderr))
|
|
throw new RuntimeException('ffprobe: ' . $stderr);
|
|
|
|
$stdout = trim(stream_get_contents($pipes[1]));
|
|
if(empty($stdout))
|
|
throw new RuntimeException('ffprobe did not report any errors but exited without any output');
|
|
} finally {
|
|
proc_close($ffprobe);
|
|
}
|
|
|
|
return json_decode($stdout);
|
|
}
|
|
|
|
public static function cleanProbe(string $url): ?object {
|
|
return self::cleanProbeResult(self::probe($url));
|
|
}
|
|
|
|
public static function cleanProbeResult(?object $in): object {
|
|
$out = new stdClass;
|
|
|
|
if(!empty($in->format)) {
|
|
$out->confidence = empty($in->format->probe_score) ? 0 : (intval($in->format->probe_score) / 100);
|
|
|
|
if(!empty($in->format->duration))
|
|
$out->duration = floatval($in->format->duration);
|
|
|
|
if(!empty($in->format->size))
|
|
$out->size = intval($in->format->size);
|
|
|
|
if(!empty($in->format->bit_rate))
|
|
$out->bitRate = intval($in->format->bit_rate);
|
|
|
|
if(!empty($in->format->tags)) {
|
|
if(!empty($in->format->tags->title)) {
|
|
$out->tagTitle = $in->format->tags->title;
|
|
} elseif(!empty($in->format->tags->TITLE)) {
|
|
$out->tagTitle = $in->format->tags->TITLE;
|
|
}
|
|
|
|
if(!empty($in->format->tags->artist)) {
|
|
$out->tagArtist = $in->format->tags->artist;
|
|
} elseif(!empty($in->format->tags->ARTIST)) {
|
|
$out->tagArtist = $in->format->tags->ARTIST;
|
|
}
|
|
|
|
if(!empty($in->format->tags->album)) {
|
|
$out->tagAlbum = $in->format->tags->album;
|
|
} elseif(!empty($in->format->tags->ALBUM)) {
|
|
$out->tagAlbum = $in->format->tags->ALBUM;
|
|
}
|
|
|
|
if(!empty($in->format->tags->date)) {
|
|
$out->tagDate = $in->format->tags->date;
|
|
} elseif(!empty($in->format->tags->DATE)) {
|
|
$out->tagDate = $in->format->tags->DATE;
|
|
}
|
|
|
|
if(!empty($in->format->tags->comment)) {
|
|
$out->tagComment = $in->format->tags->comment;
|
|
} elseif(!empty($in->format->tags->COMMENT)) {
|
|
$out->tagComment = $in->format->tags->COMMENT;
|
|
}
|
|
|
|
if(!empty($in->format->tags->genre)) {
|
|
$out->tagGenre = $in->format->tags->genre;
|
|
} elseif(!empty($in->format->tags->GENRE)) {
|
|
$out->tagGenre = $in->format->tags->GENRE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!empty($in->streams))
|
|
foreach($in->streams as $stream) {
|
|
$codecType = $stream->codec_type ?? null;
|
|
|
|
if($codecType === 'video') {
|
|
$out->width = intval($stream->coded_width ?? $stream->width ?? -1);
|
|
$out->height = intval($stream->coded_height ?? $stream->height ?? -1);
|
|
|
|
if(!empty($stream->display_aspect_ratio))
|
|
$out->aspectRatio = $stream->display_aspect_ratio;
|
|
} elseif($codecType === 'audio') {
|
|
if(!empty($stream->tags->title)) {
|
|
$out->tagTitle = $stream->tags->title;
|
|
} elseif(!empty($stream->tags->TITLE)) {
|
|
$out->tagTitle = $stream->tags->TITLE;
|
|
}
|
|
|
|
if(!empty($stream->tags->artist)) {
|
|
$out->tagArtist = $stream->tags->artist;
|
|
} elseif(!empty($stream->tags->ARTIST)) {
|
|
$out->tagArtist = $stream->tags->ARTIST;
|
|
}
|
|
|
|
if(!empty($stream->tags->album)) {
|
|
$out->tagAlbum = $stream->tags->album;
|
|
} elseif(!empty($stream->tags->ALBUM)) {
|
|
$out->tagAlbum = $stream->tags->ALBUM;
|
|
}
|
|
|
|
if(!empty($stream->tags->date)) {
|
|
$out->tagDate = $stream->tags->date;
|
|
} elseif(!empty($stream->tags->DATE)) {
|
|
$out->tagDate = $stream->tags->DATE;
|
|
}
|
|
|
|
if(!empty($stream->tags->comment)) {
|
|
$out->tagComment = $stream->tags->comment;
|
|
} elseif(!empty($stream->tags->COMMENT)) {
|
|
$out->tagComment = $stream->tags->COMMENT;
|
|
}
|
|
|
|
if(!empty($stream->tags->genre)) {
|
|
$out->tagGenre = $stream->tags->genre;
|
|
} elseif(!empty($stream->tags->GENRE)) {
|
|
$out->tagGenre = $stream->tags->GENRE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
}
|