Passed
Push — master ( e5340f...252985 )
by Sébastien
02:14
created

InterlaceDetect::guessInterlacing()   B

Complexity

Conditions 8
Paths 20

Size

Total Lines 59
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 38
CRAP Score 8.0079

Importance

Changes 0
Metric Value
eloc 40
dl 0
loc 59
ccs 38
cts 40
cp 0.95
rs 8.0355
c 0
b 0
f 0
cc 8
nc 20
nop 3
crap 8.0079

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @see       https://github.com/soluble-io/soluble-mediatools for the canonical repository
7
 *
8
 * @copyright Copyright (c) 2018-2019 Sébastien Vanvelthem. (https://github.com/belgattitude)
9
 * @license   https://github.com/soluble-io/soluble-mediatools/blob/master/LICENSE.md MIT
10
 */
11
12
namespace Soluble\MediaTools\Video\Detection;
13
14
use Soluble\MediaTools\Common\Assert\PathAssertionsTrait;
15
use Soluble\MediaTools\Common\Exception\FileNotFoundException;
16
use Soluble\MediaTools\Common\Exception\FileNotReadableException;
17
use Soluble\MediaTools\Common\IO\PlatformNullFile;
18
use Soluble\MediaTools\Common\Process\ProcessFactory;
19
use Soluble\MediaTools\Common\Process\ProcessParamsInterface;
20
use Soluble\MediaTools\Video\Config\FFMpegConfigInterface;
21
use Soluble\MediaTools\Video\Exception\AnalyzerExceptionInterface;
22
use Soluble\MediaTools\Video\Exception\AnalyzerProcessExceptionInterface;
23
use Soluble\MediaTools\Video\Exception\MissingInputFileException;
24
use Soluble\MediaTools\Video\Exception\ProcessFailedException;
25
use Soluble\MediaTools\Video\Exception\RuntimeReaderException;
26
use Soluble\MediaTools\Video\Filter\IdetVideoFilter;
27
use Soluble\MediaTools\Video\VideoConvertParams;
28
use Symfony\Component\Process\Exception as SPException;
29
30
class InterlaceDetect
31
{
32
    use PathAssertionsTrait;
33
34
    public const DEFAULT_INTERLACE_MAX_FRAMES = 1000;
35
36
    /** @var FFMpegConfigInterface */
37
    protected $ffmpegConfig;
38
39 4
    public function __construct(FFMpegConfigInterface $ffmpegConfig)
40
    {
41 4
        $this->ffmpegConfig = $ffmpegConfig;
42 4
    }
43
44
    /**
45
     * @throws AnalyzerExceptionInterface
46
     * @throws AnalyzerProcessExceptionInterface
47
     * @throws ProcessFailedException
48
     * @throws MissingInputFileException
49
     * @throws RuntimeReaderException
50
     */
51 4
    public function guessInterlacing(string $file, int $maxFramesToAnalyze = self::DEFAULT_INTERLACE_MAX_FRAMES, ?ProcessParamsInterface $processParams = null): InterlaceDetectGuess
52
    {
53 4
        $adapter = $this->ffmpegConfig->getAdapter();
54 4
        $params  = (new VideoConvertParams())
55 4
            ->withVideoFilter(new IdetVideoFilter()) // detect interlaced frames :)
56 4
            ->withVideoFrames($maxFramesToAnalyze)
57 4
            ->withNoAudio() // speed up the thing
58 4
            ->withOutputFormat('rawvideo')
59 4
            ->withOverwrite();
60
61
        try {
62 4
            $this->ensureFileReadable($file);
63
64 2
            $arguments = $adapter->getMappedConversionParams($params);
65 2
            $ffmpegCmd = $adapter->getCliCommand($arguments, $file, new PlatformNullFile());
66
67 2
            $pp = $processParams ?? $this->ffmpegConfig->getProcessParams();
68
69 2
            $process = (new ProcessFactory($ffmpegCmd, $pp))->__invoke();
70 2
            $process->mustRun();
71 3
        } catch (FileNotFoundException | FileNotReadableException $e) {
72 2
            throw new MissingInputFileException($e->getMessage());
73 1
        } catch (SPException\ProcessFailedException | SPException\ProcessTimedOutException | SPException\ProcessSignaledException $e) {
74 1
            throw new ProcessFailedException($e->getProcess(), $e);
75
        } catch (SPException\RuntimeException $e) {
76
            throw new RuntimeReaderException($e->getMessage());
77
        }
78
79 1
        $stdErr = preg_split("/(\r\n|\n|\r)/", $process->getErrorOutput());
80
81
        // Counted frames
82 1
        $interlaced_tff = 0;
83 1
        $interlaced_bff = 0;
84 1
        $progressive    = 0;
85 1
        $undetermined   = 0;
86 1
        $total_frames   = 0;
87
88 1
        if ($stdErr !== false) {
89 1
            foreach ($stdErr as $line) {
90 1
                if (mb_substr($line, 0, 12) !== '[Parsed_idet') {
91 1
                    continue;
92
                }
93
94 1
                $unspaced = sprintf('%s', preg_replace('/( )+/', '', $line));
95 1
                $matches  = [];
96 1
                if (preg_match_all('/TFF:(\d+)BFF:(\d+)Progressive:(\d+)Undetermined:(\d+)/i', $unspaced, $matches) < 1) {
97 1
                    continue;
98
                }
99
100
                //$type = strpos(strtolower($unspaced), 'single') ? 'single' : 'multi';
101 1
                $interlaced_tff += (int) $matches[1][0];
102 1
                $interlaced_bff += (int) $matches[2][0];
103 1
                $progressive += (int) $matches[3][0];
104 1
                $undetermined += (int) $matches[4][0];
105 1
                $total_frames += ((int) $matches[1][0] + (int) $matches[2][0] + (int) $matches[3][0] + (int) $matches[4][0]);
106
            }
107
        }
108
109 1
        return new InterlaceDetectGuess($interlaced_tff, $interlaced_bff, $progressive, $undetermined);
110
    }
111
}
112