Passed
Push — master ( bc6590...e618e7 )
by Amin
05:42 queued 11s
created

Metadata::getJson()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of the PHP-FFmpeg-video-streaming package.
5
 *
6
 * (c) Amin Yazdanpanah <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
13
namespace Streaming;
14
15
16
use FFMpeg\FFProbe\DataMapping\Format;
17
use FFMpeg\FFProbe\DataMapping\Stream as VideoStream;
18
use FFMpeg\FFProbe\DataMapping\StreamCollection;
19
use Streaming\Exception\InvalidArgumentException;
20
21
class Metadata
22
{
23
    /** @var Stream */
24
    private $stream;
25
26
    /** @var \FFMpeg\FFProbe\DataMapping\Format */
27
    private $format;
28
29
    /** @var \FFMpeg\FFProbe\DataMapping\StreamCollection */
30
    private $video_streams;
31
32
    /**
33
     * Metadata constructor.
34
     * @param Stream $stream
35
     */
36
    public function __construct(Stream $stream)
37
    {
38
        $this->stream = $stream;
39
        $this->format = $stream->getMedia()->getFormat();
0 ignored issues
show
Documentation Bug introduced by
It seems like $stream->getMedia()->getFormat() of type FFMpeg\Media\Video or Streaming\Media is incompatible with the declared type FFMpeg\FFProbe\DataMapping\Format of property $format.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
Bug introduced by
The method getFormat() does not exist on Streaming\Media. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

39
        $this->format = $stream->getMedia()->/** @scrutinizer ignore-call */ getFormat();
Loading history...
40
        $this->video_streams = $stream->getMedia()->getStreams();
0 ignored issues
show
Documentation Bug introduced by
It seems like $stream->getMedia()->getStreams() of type FFMpeg\Media\Video or Streaming\Media is incompatible with the declared type FFMpeg\FFProbe\DataMapping\StreamCollection of property $video_streams.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
Bug introduced by
The method getStreams() does not exist on Streaming\Media. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

40
        $this->video_streams = $stream->getMedia()->/** @scrutinizer ignore-call */ getStreams();
Loading history...
41
    }
42
43
    /**
44
     * @return \FFMpeg\FFProbe\DataMapping\Format
45
     */
46
    public function getFormat(): Format
47
    {
48
        return $this->format;
49
    }
50
51
    /**
52
     * @return \FFMpeg\FFProbe\DataMapping\StreamCollection
53
     */
54
    public function getVideoStreams(): StreamCollection
55
    {
56
        return $this->video_streams;
57
    }
58
59
    /**
60
     * @param VideoStream $stream
61
     * @return array
62
     */
63
    private function streamToArray(VideoStream $stream): array
64
    {
65
        return $stream->all();
66
    }
67
68
    /**
69
     * @return mixed
70
     */
71
    private function getVideoMetadata(): array
72
    {
73
        return [
74
            'format' => $this->getFormat()->all(),
75
            'streams' => array_map([$this, 'streamToArray'], $this->getVideoStreams()->all())
76
        ];
77
    }
78
79
    /**
80
     * @param Representation $rep
81
     * @return array
82
     */
83
    private function repToArray(Representation $rep): array
84
    {
85
        return [
86
            "dimension" => strtoupper($rep->size2string()),
87
            "video_kilo_bitrate" => $rep->getKiloBitrate(),
88
            "audio_kilo_bitrate" => $rep->getAudioKiloBitrate() ?? "Not specified"
89
        ];
90
    }
91
92
    /**
93
     * @return array
94
     */
95
    private function getResolutions(): array
96
    {
97
        if (!method_exists($this->stream, 'getRepresentations')) {
98
            return [];
99
        }
100
101
        return array_map([$this, 'repToArray'], $this->stream->getRepresentations()->all());
102
    }
103
104
105
    /**
106
     * @return array
107
     */
108
    public function getStreamsMetadata(): array
109
    {
110
        $dirname = $this->stream->pathInfo(PATHINFO_DIRNAME);
111
        $basename = $this->stream->pathInfo(PATHINFO_BASENAME);
112
        $filename = $dirname . DIRECTORY_SEPARATOR . $basename;
113
114
        $technique = explode("\\", get_class($this->stream));
115
        $format = explode("\\", get_class($this->stream->getFormat()));
116
117
        $metadata = [
118
            "filename" => $filename,
119
            "size_of_stream_dir" => File::directorySize($dirname),
120
            "created_at" => file_exists($filename) ? date("Y-m-d H:i:s", filemtime($filename)) : 'The file has been deleted',
121
            "resolutions" => $this->getResolutions(),
122
            "format" => end($format),
123
            "streaming_technique" => end($technique)
124
        ];
125
126
        if ($this->stream instanceof DASH) {
127
            $metadata = array_merge($metadata, ["seg_duration" => $this->stream->getSegDuration()]);
128
        } elseif ($this->stream instanceof HLS) {
129
            $metadata = array_merge(
130
                $metadata,
131
                [
132
                    "hls_time" => (int)$this->stream->getHlsTime(),
133
                    "hls_cache" => (bool)$this->stream->isHlsAllowCache(),
134
                    "encrypted_hls" => (bool)$this->stream->getHlsKeyInfoFile(),
135
                    "ts_sub_directory" => $this->stream->getSegSubDirectory(),
136
                    "base_url" => $this->stream->getHlsBaseUrl()
137
                ]
138
            );
139
        }
140
141
        return $metadata;
142
    }
143
144
    /**
145
     * @return array
146
     */
147
    public function get(): array
148
    {
149
        return [
150
            "video" => $this->getVideoMetadata(),
151
            "stream" => $this->getStreamsMetadata()
152
        ];
153
    }
154
155
    /**
156
     * @param null $opts
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $opts is correct as it would always require null to be passed?
Loading history...
157
     * @return string
158
     */
159
    public function getJson($opts = null): string
160
    {
161
        return json_encode($this->get(), $opts ?? JSON_PRETTY_PRINT);
162
    }
163
164
    /**
165
     * @param string $filename
166
     * @param int $opts
167
     * @return string
168
     */
169
    public function saveAsJson(string $filename = null, int $opts = null): string
170
    {
171
        if (is_null($filename)) {
172
            if ($this->stream->isTmpDir()) {
173
                throw new InvalidArgumentException("It is a temp directory! It is not possible to save it");
174
            }
175
176
            $name = uniqid(($this->stream->pathInfo(PATHINFO_FILENAME) ?? "meta") . "-") . ".json";
177
            $filename = $this->stream->pathInfo(PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR . $name;
178
        }
179
        File::put($filename, $this->getJson($opts));
0 ignored issues
show
Bug introduced by
It seems like $opts can also be of type integer; however, parameter $opts of Streaming\Metadata::getJson() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

179
        File::put($filename, $this->getJson(/** @scrutinizer ignore-type */ $opts));
Loading history...
180
181
        return $filename;
182
    }
183
184
    /**
185
     * @param string|null $save_to
186
     * @param int|null $opts
187
     * @return array
188
     */
189
    public function export(string $save_to = null, int $opts = null): array
190
    {
191
        return array_merge($this->get(), ['filename' => $this->saveAsJson($save_to, $opts)]);
192
    }
193
}