Passed
Push — master ( dc3048...353d8c )
by Sébastien
03:11
created

VideoInfo::createFromFFProbeJson()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.2098

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 2
dl 0
loc 11
ccs 5
cts 7
cp 0.7143
crap 3.2098
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Soluble\MediaTools\Video;
6
7
use Soluble\MediaTools\Common\Exception\IOException;
8
use Soluble\MediaTools\Common\Exception\JsonParseException;
9
10
class VideoInfo implements VideoInfoInterface
11
{
12
    public const STREAM_TYPE_AUDIO = 'audio';
13
    public const STREAM_TYPE_VIDEO = 'video';
14
    public const STREAM_TYPE_DATA  = 'data';
15
16
    /** @var array */
17
    protected $metadata;
18
19
    /** @var string */
20
    protected $file;
21
22 3
    public function __construct(string $file, array $metadata)
23
    {
24 3
        $this->metadata = $metadata;
25 3
        $this->file     = $file;
26 3
    }
27
28 1
    public static function createFromFFProbeJson(string $file, string $ffprobeJson): self
29
    {
30 1
        if (trim($ffprobeJson) === '') {
31
            throw new JsonParseException('Cannot parse empty json string');
32
        }
33 1
        $decoded = json_decode($ffprobeJson, true);
34 1
        if ($decoded === null) {
35
            throw new JsonParseException('Cannot parse json');
36
        }
37
38 1
        return new self($file, $decoded);
39
    }
40
41 2
    public function getFile(): string
42
    {
43 2
        return $this->file;
44
    }
45
46
    /**
47
     * @throws IOException
48
     */
49 2
    public function getFileSize(): int
50
    {
51 2
        $size = @filesize($this->file);
52 2
        if ($size === false) {
53 1
            throw new IOException(sprintf(
54 1
                'Cannot get filesize of file %s',
55 1
                $this->file
56
            ));
57
        }
58
59 1
        return $size;
60
    }
61
62 1
    public function getFormatName(): string
63
    {
64 1
        return $this->metadata['format']['format_name'];
65
    }
66
67 1
    public function countStreams(): int
68
    {
69 1
        return $this->metadata['format']['nb_streams'];
70
    }
71
72
    public function getMetadata(): array
73
    {
74
        return $this->metadata;
75
    }
76
77 1
    public function getDuration(): float
78
    {
79 1
        return (float) ($this->metadata['format']['duration'] ?? 0.0);
80
    }
81
82 1
    public function getDimensions(): array
83
    {
84
        return [
85 1
            'width'  => $this->getWidth(),
86 1
            'height' => $this->getHeight(),
87
        ];
88
    }
89
90 1
    public function getWidth(): int
91
    {
92 1
        $videoStream = $this->getVideoStreamInfo();
93
94 1
        return (int) ($videoStream['width'] ?? 0);
95
    }
96
97 1
    public function getHeight(): int
98
    {
99 1
        $videoStream = $this->getVideoStreamInfo();
100
101 1
        return (int) ($videoStream['height'] ?? 0);
102
    }
103
104 1
    public function getNbFrames(): int
105
    {
106 1
        $videoStream = $this->getVideoStreamInfo();
107
108 1
        return (int) ($videoStream['nb_frames'] ?? 0);
109
    }
110
111
    public function getBitrate(): int
112
    {
113
        $videoStream = $this->getVideoStreamInfo();
114
115
        return (int) ($videoStream['bit_rate'] ?? 0);
116
    }
117
118
    public function getAudioStreamInfo(): ?array
119
    {
120
        return $this->getStreamsByType()[self::STREAM_TYPE_AUDIO] ?? null;
121
    }
122
123 1
    public function getVideoStreamInfo(): ?array
124
    {
125 1
        return $this->getStreamsByType()[self::STREAM_TYPE_VIDEO] ?? null;
126
    }
127
128 1
    protected function getStreamsByType(): array
129
    {
130 1
        $streams = $this->metadata['streams'] ?? [];
131 1
        foreach ($streams as $stream) {
132 1
            $type = mb_strtolower($stream['codec_type']);
133
            switch ($type) {
134 1
                case self::STREAM_TYPE_VIDEO:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
135 1
                    $streams['video'] = $stream;
136 1
                    break;
137 1
                case self::STREAM_TYPE_AUDIO:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
138 1
                    $streams['audio'] = $stream;
139 1
                    break;
140
                case self::STREAM_TYPE_DATA:
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
141
                    $streams['data'] = $stream;
142
                    break;
143
                default:
0 ignored issues
show
Coding Style introduced by
DEFAULT statements must be defined using a colon

As per the PSR-2 coding standard, default statements should not be wrapped in curly braces.

switch ($expr) {
    default: { //wrong
        doSomething();
        break;
    }
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
144 1
                    throw new \Exception(sprintf('Does not support codec_type "%s"', $type));
145
            }
146
        }
147
148 1
        return $streams;
149
    }
150
}
151