laravel-ffmpeg
laravel-ffmpeg copied to clipboard
While resizing vertical video ResizeFilter mode is being ignored or not produce expected results
Hello, I'm struggling with resizing vertical video - no matter what setting I use, exit file have fixed dimensions and it's being stretched.
Bellow is input file (shoot from iPhone holding phone vertically)
This is output file: (dimensions are reversed - it's being width in 1080)
Of course tried swapping width with height, and change scale mode to width, height - but I never give me expected results.
I would expect to have 1080p heigh vertical video - with any width needed to preserve original aspect ratio.
Original video was short on iPhone and it contain tag "rotate:90" <- maybe this is confusing laravel-ffmpeg?
This is my code:
FFMpeg::fromDisk(Storage::disk('local'))->open('org.MOV')
->export()
->inFormat(new \FFMpeg\Format\Video\X264)
->addFilter(function (VideoFilters $filters) {
$filters->resize(new \FFMpeg\Coordinate\Dimension(1080,1920 ),ResizeFilter::RESIZEMODE_SCALE_HEIGHT, false);
})
->toDisk('local')
->save('steve_howe_resized.mp4');
Little bit about env:
laravel-ffmpeg version 8.0.1 ffmpeg version 4.2.4-1ubuntu0.1 Copyright (c) 2000-2020 the FFmpeg developers
I can upload sample video for investigation.
Any idea will be appreciated :>
Can you share the video?
Hello, Thank You for reply, Sure here is download link to RAW video:
https://easyupload.io/0valiv
(it's less than 10 seconds but in 4K - i don't do any compression or encoding)
I wrote workaround for it, this is code that make me happy and resolved my issue:
foreach ($resolutionsToProcess as $resolution) {
FFMpeg::fromDisk(Storage::disk('local'))->open($this->filePath)
->export()
->inFormat($resolution[3])
->addFilter(function ($filters) use ($resolution) {
if ($this->isHorizontal) {
$filters->custom('scale=trunc(oh*a/2)*2:' . (string)$resolution[0]);
} else {
$filters->custom('scale=' . (string)$resolution[0] . ':trunc(ow/a/2)*2');
}
})
->toDisk('s3')
->save($this->uuid . '/' . $resolution[2] . $resolution[4]);
}
Those were magic lines:
if ($this->isHorizontal) {
$filters->custom('scale=trunc(oh*a/2)*2:' . (string)$resolution[0]);
} else {
$filters->custom('scale=' . (string)$resolution[0] . ':trunc(ow/a/2)*2');
}
isHorizontal - i wrote by myself
` public function isHorizontal(): bool
{
$dimensions = FFMpeg::fromDisk('local')->open($this->filePath)->getVideoStream()->all();
if (isset($dimensions['tags']['rotate']) && $dimensions['tags']['rotate'] == 90) {
return true;
} else {
return false;
}
}
I have no idea is this good approach but this application is only used by me and I only upload iPhone videos for my workflow so i have not tested it on anything else.
i had the same issues.
the culprit lays on the php-ffmpeg site.
i changed inside ffprobe :
vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFProbe/DataMapping/Stream.php
public function getDimensions()
{
if (!$this->isVideo()) {
throw new LogicException('Dimensions can only be retrieved from video streams.');
}
$sampleRatio = $displayRatio = null;
$width = $this->get('width');
$height = $this->get('height');
$tags = $this->get('tags');
if (empty($tags['rotate'])) {
// dump('no rota');
} else {
// dump('rooo' . intval($tags['rotate']));
$checkRot = intval($tags['rotate']);
if ((90 === $checkRot) || (-90 === $checkRot) || (270 === $checkRot)) {
$width = $this->get('height');
$height = $this->get('width');
}
}
if (null === $height || null === $width) {
throw new RuntimeException('Unable to extract dimensions.');
}
return new Dimension($width, $height);
// if (null !== $ratio = $this->extractRatio($this, 'sample_aspect_ratio')) {
// $sampleRatio = $ratio;
// }
// if (null !== $ratio = $this->extractRatio($this, 'display_aspect_ratio')) {
// $displayRatio = $ratio;
// }
// if (null === $height || null === $width) {
// throw new RuntimeException('Unable to extract dimensions.');
// }
// if (null !== $displayRatio && null !== $sampleRatio) {
// if (1 !== $sampleRatio[0] && 1 !== $sampleRatio[1]) {
// if (null !== $width && null !== $height) {
// // stretch video according to pixel sample aspect ratio
// $width = round($width * ($sampleRatio[0] / $sampleRatio[1]));
// // set height according to display aspect ratio
// $height = round($width * ($displayRatio[1] / $displayRatio[0]));
// }
// }
// }
// return new Dimension($width, $height);
}
/**
* Returns the rotation of the video stream, in degrees.
* Use this to determine if the dimensions are rotated.
*
* @return Integer
*
* @throws LogicException In case the stream is not a video stream.
*/
public function getRotation()
{
if (!$this->isVideo()) {
throw new LogicException('Rotation can only be retrieved from video streams.');
}
$tags = $this->get('tags');
if (empty($tags['rotate'])) {
return 0;
}
return intval($tags['rotate']);
}