VideoStream::getProfile()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
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
final 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 11
    public function __construct(array $streamMetadata, ?LoggerInterface $logger = null)
24
    {
25 11
        $this->streamMetadata = $streamMetadata;
26 11
        $this->tsReader       = new MetadataTypeSafeReader($streamMetadata, $logger);
27 11
    }
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
86
        try {
87 1
            $dispAr = str_replace('/', AspectRatio::DEFAULT_PROPORTION_SEPARATOR, $dispAr);
88
89 1
            return AspectRatio::createFromString($dispAr, AspectRatio::DEFAULT_PROPORTION_SEPARATOR);
90
        } catch (InvalidArgumentException $e) {
91
            return null;
92
        }
93
    }
94
95 1
    public function getSampleAspectRatio(): ?string
96
    {
97 1
        return $this->tsReader->getKeyStringOrNullValue('sample_aspect_ratio');
98
    }
99
100 1
    public function getDisplayAspectRatio(): ?string
101
    {
102 1
        return $this->tsReader->getKeyStringOrNullValue('display_aspect_ratio');
103
    }
104
105 3
    public function getPixFmt(): ?string
106
    {
107 3
        return $this->tsReader->getKeyStringOrNullValue('pix_fmt');
108
    }
109
110 1
    public function getAvgFrameRate(): ?string
111
    {
112 1
        return $this->tsReader->getKeyStringOrNullValue('avg_frame_rate');
113
    }
114
115 2
    public function getRFrameRate(): ?string
116
    {
117 2
        return $this->tsReader->getKeyStringOrNullValue('r_frame_rate');
118
    }
119
120 1
    public function getTimeBase(): ?string
121
    {
122 1
        return $this->tsReader->getKeyStringOrNullValue('time_base');
123
    }
124
125 1
    public function getDurationTs(): ?int
126
    {
127 1
        return $this->tsReader->getKeyIntOrNullValue('duration_ts');
128
    }
129
130 2
    public function getDuration(): float
131
    {
132
        try {
133 2
            return $this->tsReader->getKeyFloatValue('duration');
134 1
        } catch (UnexpectedMetadataException $e) {
135 1
            return 0;
136
        }
137
    }
138
139 1
    public function getProfile(): ?string
140
    {
141 1
        return $this->tsReader->getKeyStringOrNullValue('profile');
142
    }
143
144 3
    public function getBitRate(): ?int
145
    {
146 3
        return $this->tsReader->getKeyIntOrNullValue('bit_rate');
147
    }
148
149 4
    public function getNbFrames(): ?int
150
    {
151 4
        return $this->tsReader->getKeyIntOrNullValue('nb_frames');
152
    }
153
154 2
    public function isAvc(): ?bool
155
    {
156 2
        if (!isset($this->streamMetadata['is_avc'])) {
157 2
            return null;
158
        }
159
160 1
        return $this->streamMetadata['is_avc'] === 'true';
161
    }
162
163 1
    public function getLevel(): ?int
164
    {
165 1
        return $this->tsReader->getKeyIntOrNullValue('level');
166
    }
167
168 1
    public function getStartTime(): ?float
169
    {
170 1
        return $this->tsReader->getKeyFloatOrNullValue('start_time');
171
    }
172
173 1
    public function getColorRange(): ?string
174
    {
175 1
        return $this->tsReader->getKeyStringOrNullValue('color_range');
176
    }
177
178 1
    public function getColorSpace(): ?string
179
    {
180 1
        return $this->tsReader->getKeyStringOrNullValue('color_space');
181
    }
182
183 1
    public function getColorTransfer(): ?string
184
    {
185 1
        return $this->tsReader->getKeyStringOrNullValue('color_transfer');
186
    }
187
188 1
    public function getDimensions(): array
189
    {
190
        return [
191 1
            'width'  => $this->getWidth(),
192 1
            'height' => $this->getHeight(),
193
        ];
194
    }
195
196 1
    public function getFps(?int $decimals = null): ?float
197
    {
198 1
        $rFrame = $this->getRFrameRate();
199 1
        $fps    = null;
200
201 1
        if ($rFrame !== null && preg_match('/^[0-9]+\/[0-9]+$/', $rFrame) !== false) {
202
            // Let's use the rframe_rate
203 1
            [$frames, $base] = explode('/', $rFrame);
204 1
            if (is_numeric($base) && $base > 0 && is_numeric($frames) && $frames > 0) {
205 1
                $tmp = (float) ((int) $frames / (int) $base);
206 1
                if ($tmp > 1000 && $this->getFpsFromDuration() !== null) {
207
                    // sometimes a bug with samsung smartphone (i.e: 9000fps)
208 1
                    $fps = $this->getFpsFromDuration();
209
                } else {
210 1
                    $fps = $tmp;
211
                }
212
            }
213
        }
214
215 1
        if ($fps === null) {
216 1
            $fps = $this->getFpsFromDuration();
217
        }
218
219 1
        if ($decimals !== null && $fps !== null) {
220 1
            $fps = round($fps, $decimals);
221
        }
222
223 1
        return $fps;
224
    }
225
226 1
    private function getFpsFromDuration(): ?float
227
    {
228 1
        if (($this->getNbFrames() ?? 0) > 0 && ($this->getDuration()) > 0) {
229 1
            return (float) $this->getNbFrames() / $this->getDuration();
230
        }
231
232 1
        return null;
233
    }
234
235
    /**
236
     * @return array<string, string>
237
     */
238 1
    public function getTags(): array
239
    {
240 1
        return $this->streamMetadata['tags'] ?? [];
241
    }
242
243
    /**
244
     * Return underlying ffprobe json metadata.
245
     *
246
     * @return array<string, mixed>
247
     */
248 1
    public function getStreamMetadata(): array
249
    {
250 1
        return $this->streamMetadata;
251
    }
252
}
253