uiharu/src/FFMPEG.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;
}
}