Files
2026-09-15 10:35:56 +08:00

73 lines
2.3 KiB
PHP

<?php
declare(strict_types=1);
namespace Esun\Video\Model;
use Magento\Framework\Exception\LocalizedException;
use Symfony\Component\Process\Process;
class Ffprobe
{
public function __construct(private readonly Config $config)
{
}
public function inspect(string $absoluteFile): array
{
$process = new Process([
$this->config->getFfprobeBinary(),
'-v', 'error',
'-select_streams', 'v:0',
'-show_entries', 'format=format_name,duration,size:stream=width,height,codec_name',
'-of', 'json',
$absoluteFile,
]);
$process->setTimeout(60);
try {
$process->run();
} catch (\Throwable $e) {
throw new LocalizedException(__('Unable to run ffprobe: %1', $e->getMessage()));
}
if (!$process->isSuccessful()) {
throw new LocalizedException(
__('ffprobe failed: %1', trim($process->getErrorOutput()) ?: __('unknown error'))
);
}
$data = json_decode($process->getOutput(), true);
$stream = $data['streams'][0] ?? [];
$format = $data['format'] ?? [];
$formatName = strtolower((string)($format['format_name'] ?? ''));
if (!str_contains($formatName, 'mp4') && !str_contains($formatName, 'mov')) {
throw new LocalizedException(__('Only MP4 container files are supported.'));
}
$width = (int)($stream['width'] ?? 0);
$height = (int)($stream['height'] ?? 0);
if ($width <= 0 || $height <= 0) {
throw new LocalizedException(__('The MP4 file does not contain a readable video stream.'));
}
return [
'duration' => round((float)($format['duration'] ?? 0), 3),
'size' => (int)($format['size'] ?? filesize($absoluteFile)),
'width' => $width,
'height' => $height,
'resolution' => $this->getResolution($width, $height),
];
}
private function getResolution(int $width, int $height): string
{
$longEdge = max($width, $height);
$shortEdge = min($width, $height);
if ($longEdge >= 3840 || $shortEdge >= 2160) {
return '4K';
}
if ($longEdge >= 1920 || $shortEdge >= 1080) {
return '1080p';
}
return $shortEdge . 'p';
}
}