laravel-ffmpeg icon indicating copy to clipboard operation
laravel-ffmpeg copied to clipboard

While resizing vertical video ResizeFilter mode is being ignored or not produce expected results

Open opzsgu opened this issue 2 years ago • 3 comments

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) input_file

This is output file: (dimensions are reversed - it's being width in 1080)

output_file

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 :>

opzsgu avatar May 03 '22 13:05 opzsgu

Can you share the video?

pascalbaljet avatar May 13 '22 07:05 pascalbaljet

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.

opzsgu avatar May 13 '22 07:05 opzsgu

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']);
    }

ibrainventures avatar May 24 '22 20:05 ibrainventures