Completed
Push — master ( 200706...461174 )
by Sébastien
07:33
created

VideoStream::getFps()   C

Complexity

Conditions 12
Paths 16

Size

Total Lines 28
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 12

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 28
ccs 15
cts 15
cp 1
rs 6.9666
c 0
b 0
f 0
cc 12
nc 16
nop 1
crap 12

How to fix   Complexity   

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
namespace Soluble\MediaTools\Video\Info;
6
7
use Psr\Log\LoggerInterface;
8
use Soluble\MediaTools\Video\Exception\InvalidArgumentException;
9
use Soluble\MediaTools\Video\Exception\UnexpectedMetadataException;
10
use Soluble\MediaTools\Video\Info\Util\MetadataTypeSafeReader;
11
12
class VideoStream implements VideoStreamInterface
13
{
14
    /** @var array<string, mixed> */
15
    private $streamMetadata;
16
17
    /** @var MetadataTypeSafeReader */
18
    private $tsReader;
19
20
    /**
21
     * @param array<string, mixed> $streamMetadata
22
     */
23 10
    public function __construct(array $streamMetadata, ?LoggerInterface $logger = null)
24
    {
25 10
        $this->streamMetadata = $streamMetadata;
26 10
        $this->tsReader       = new MetadataTypeSafeReader($streamMetadata, $logger);
27 10
    }
28
29 2
    public function getIndex(): int
30
    {
31 2
        return $this->tsReader->getKeyIntValue('index');
32
    }
33
34 2
    public function getCodecType(): string
35
    {
36 2
        return $this->tsReader->getKeyStringValue('codec_type');
37
    }
38
39 2
    public function getCodecName(): string
40
    {
41 2
        return $this->tsReader->getKeyStringValue('codec_name');
42
    }
43
44 1
    public function getCodecLongName(): ?string
45
    {
46 1
        return $this->tsReader->getKeyStringOrNullValue('codec_long_name');
47
    }
48
49 1
    public function getCodecTimeBase(): ?string
50
    {
51 1
        return $this->tsReader->getKeyStringOrNullValue('codec_time_base');
52
    }
53
54 1
    public function getCodecTagString(): ?string
55
    {
56 1
        return $this->tsReader->getKeyStringOrNullValue('codec_tag_string');
57
    }
58
59 4
    public function getWidth(): int
60
    {
61 4
        return $this->tsReader->getKeyIntValue('width');
62
    }
63
64 4
    public function getHeight(): int
65
    {
66 4
        return $this->tsReader->getKeyIntValue('height');
67
    }
68
69 1
    public function getCodedWidth(): ?int
70
    {
71 1
        return $this->tsReader->getKeyIntOrNullValue('coded_width');
72
    }
73
74 1
    public function getCodedHeight(): ?int
75
    {
76 1
        return $this->tsReader->getKeyIntOrNullValue('coded_height');
77
    }
78
79 1
    public function getAspectRatio(): ?AspectRatio
80
    {
81 1
        $dispAr = $this->getDisplayAspectRatio();
82 1
        if ($dispAr === null) {
83
            return null;
84
        }
85
        try {
86 1
            $dispAr = str_replace('/', AspectRatio::DEFAULT_PROPORTION_SEPARATOR, $dispAr);
87
88 1
            return AspectRatio::createFromString($dispAr, AspectRatio::DEFAULT_PROPORTION_SEPARATOR);
89
        } catch (InvalidArgumentException $e) {
90
            return null;
91
        }
92
    }
93
94 1
    public function getSampleAspectRatio(): ?string
95
    {
96 1
        return $this->tsReader->getKeyStringOrNullValue('sample_aspect_ratio');
97
    }
98
99 1
    public function getDisplayAspectRatio(): ?string
100
    {
101 1
        return $this->tsReader->getKeyStringOrNullValue('display_aspect_ratio');
102
    }
103
104 3
    public function getPixFmt(): ?string
105
    {
106 3
        return $this->tsReader->getKeyStringOrNullValue('pix_fmt');
107
    }
108
109 1
    public function getAvgFrameRate(): ?string
110
    {
111 1
        return $this->tsReader->getKeyStringOrNullValue('avg_frame_rate');
112
    }
113
114 2
    public function getRFrameRate(): ?string
115
    {
116 2
        return $this->tsReader->getKeyStringOrNullValue('r_frame_rate');
117
    }
118
119 1
    public function getTimeBase(): ?string
120
    {
121 1
        return $this->tsReader->getKeyStringOrNullValue('time_base');
122
    }
123
124 1
    public function getDurationTs(): ?int
125
    {
126 1
        return $this->tsReader->getKeyIntOrNullValue('duration_ts');
127
    }
128
129 2
    public function getDuration(): float
130
    {
131
        try {
132 2
            return $this->tsReader->getKeyFloatValue('duration');
133 1
        } catch (UnexpectedMetadataException $e) {
134 1
            return 0;
135
        }
136
    }
137
138 1
    public function getProfile(): ?string
139
    {
140 1
        return $this->tsReader->getKeyStringOrNullValue('profile');
141
    }
142
143 3
    public function getBitRate(): ?int
144
    {
145 3
        return $this->tsReader->getKeyIntOrNullValue('bit_rate');
146
    }
147
148 3
    public function getNbFrames(): ?int
149
    {
150 3
        return $this->tsReader->getKeyIntOrNullValue('nb_frames');
151
    }
152
153 2
    public function isAvc(): ?bool
154
    {
155 2
        if (!isset($this->streamMetadata['is_avc'])) {
156 2
            return null;
157
        }
158
159 1
        return $this->streamMetadata['is_avc'] === 'true';
160
    }
161
162 1
    public function getLevel(): ?int
163
    {
164 1
        return $this->tsReader->getKeyIntOrNullValue('level');
165
    }
166
167 1
    public function getStartTime(): ?float
168
    {
169 1
        return $this->tsReader->getKeyFloatOrNullValue('start_time');
170
    }
171
172 1
    public function getColorRange(): ?string
173
    {
174 1
        return $this->tsReader->getKeyStringOrNullValue('color_range');
175
    }
176
177 1
    public function getColorSpace(): ?string
178
    {
179 1
        return $this->tsReader->getKeyStringOrNullValue('color_space');
180
    }
181
182 1
    public function getColorTransfer(): ?string
183
    {
184 1
        return $this->tsReader->getKeyStringOrNullValue('color_transfer');
185
    }
186
187 1
    public function getDimensions(): array
188
    {
189
        return [
190 1
            'width'  => $this->getWidth(),
191 1
            'height' => $this->getHeight(),
192
        ];
193
    }
194
195 1
    public function getFps(?int $decimals = null): ?float
196
    {
197 1
        $rFrame = $this->getRFrameRate();
198 1
        $fps    = null;
199
200 1
        if ($rFrame !== null && preg_match('/^[0-9]+\/[0-9]+$/', $rFrame) !== false) {
201
            // Let's use the rframe_rate
202 1
            [$frames, $base] = explode('/', $rFrame);
203 1
            if (is_numeric($base) && $base > 0 && is_numeric($frames) && $frames > 0) {
204 1
                $tmp = (float) ((int) $frames / (int) $base);
205 1
                if ($tmp > 1000 && $this->getFpsFromDuration() !== null) {
206
                    // sometimes a bug with samsung smartphone (i.e: 9000fps)
207 1
                    $fps = $this->getFpsFromDuration();
208
                } else {
209 1
                    $fps = $tmp;
210
                }
211
            }
212
        }
213
214 1
        if ($fps === null) {
215 1
            $fps = $this->getFpsFromDuration();
216
        }
217
218 1
        if ($decimals !== null && $fps !== null) {
219 1
            $fps = round($fps, $decimals);
220
        }
221
222 1
        return $fps;
223
    }
224
225 1
    private function getFpsFromDuration(): ?float
226
    {
227 1
        if (($this->getNbFrames() ?? 0) > 0 && ($this->getDuration() ?? 0) > 0) {
228 1
            return (float) $this->getNbFrames() / $this->getDuration();
229
        }
230
231 1
        return null;
232
    }
233
234
    /**
235
     * @return array<string, string>
236
     */
237 1
    public function getTags(): array
238
    {
239 1
        return $this->streamMetadata['tags'] ?? [];
240
    }
241
242
    /**
243
     * Return underlying ffprobe json metadata.
244
     *
245
     * @return array<string, mixed>
246
     */
247 1
    public function getStreamMetadata(): array
248
    {
249 1
        return $this->streamMetadata;
250
    }
251
}
252