Passed
Push — master ( 79d402...4ebce0 )
by Amin
01:15
created

ffmpeg_streaming.ffprobe.Streams.all()   A

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 5
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 1
dl 5
loc 5
rs 10
c 0
b 0
f 0
1
"""
2
ffmpeg_streaming._ffprobe
3
~~~~~~~~~~~~
4
5
Probe the video
6
7
8
:copyright: (c) 2020 by Amin Yazdanpanah.
9
:website: https://www.aminyazdanpanah.com
10
:email: [email protected]
11
:license: MIT, see LICENSE for more details.
12
"""
13
14
import json
15
import logging
16
import subprocess
17
18
from ._media_property import Size, Bitrate
19
20
21 View Code Duplication
class Streams:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
22
    def __init__(self, streams):
23
        self.streams = streams
24
25
    def video(self, ignore_error=True):
26
        """
27
        @TODO: add documentation
28
        """
29
        return self._get_stream('video', ignore_error)
30
31
    def audio(self, ignore_error=True):
32
        """
33
        @TODO: add documentation
34
        """
35
        return self._get_stream('audio', ignore_error)
36
37
    def first_stream(self):
38
        """
39
        @TODO: add documentation
40
        """
41
        return self.streams[0]
42
43
    def all(self):
44
        """
45
        @TODO: add documentation
46
        """
47
        return self.streams
48
49
    def videos(self):
50
        """
51
        @TODO: add documentation
52
        """
53
        return self._get_streams('video')
54
55
    def audios(self):
56
        """
57
        @TODO: add documentation
58
        """
59
        return self._get_streams('audio')
60
61
    def _get_stream(self, media, ignore_error):
62
        """
63
        @TODO: add documentation
64
        """
65
        media_attr = next((stream for stream in self.streams if stream['codec_type'] == media), None)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable stream does not seem to be defined.
Loading history...
66
        if media_attr is None and not ignore_error:
67
            raise ValueError('No ' + str(media) + ' stream found')
68
        return media_attr if media_attr is not None else {}
69
70
    def _get_streams(self, media):
71
        """
72
        @TODO: add documentation
73
        """
74
        for stream in self.streams:
75
            if stream['codec_type'] == media:
76
                yield stream
77
78
79
class FFProbe:
80
    def __init__(self, filename, cmd='ffprobe'):
81
        """
82
        @TODO: add documentation
83
        """
84
        commands = [cmd, '-show_format', '-show_streams', '-of', 'json', filename]
85
        logging.info("ffprobe running command: {}".format(" ".join(commands)))
86
        process = subprocess.Popen(commands, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
87
        self.out, err = process.communicate()
88
        if process.returncode != 0:
89
            logging.error(str(self.out) + str(err))
90
            raise RuntimeError('ffprobe', self.out, err)
91
        logging.info("ffprobe executed command successfully!")
92
93
    def streams(self):
94
        """
95
        @TODO: add documentation
96
        """
97
        return Streams(json.loads(self.out.decode('utf-8'))['streams'])
98
99
    def format(self):
100
        """
101
        @TODO: add documentation
102
        """
103
        return json.loads(self.out.decode('utf-8'))['format']
104
105
    def all(self):
106
        """
107
        @TODO: add documentation
108
        """
109
        return json.loads(self.out.decode('utf-8'))
110
111
    def save_as_json(self, path):
112
        """
113
        @TODO: add documentation
114
        """
115
        with open(path, 'w') as probe:
116
            probe.write(self.out.decode('utf-8'))
117
118
    @property
119
    def video_size(self) -> Size:
120
        """
121
        @TODO: add documentation
122
        """
123
        width = int(self.streams().video().get('width', 0))
124
        height = int(self.streams().video().get('height', 0))
125
126
        if width == 0 or height == 0:
127
            raise RuntimeError('It could not determine the value of width/height')
128
129
        return Size(width, height)
130
131
    @property
132
    def bitrate(self, _type: str = "k") -> Bitrate:
133
        """
134
        @TODO: add documentation
135
        """
136
        overall = int(self.format().get('bit_rate', 0))
137
        video = int(self.streams().video().get('bit_rate', 0))
138
        audio = int(self.streams().audio().get('bit_rate', 0))
139
140
        if overall == 0:
141
            raise RuntimeError('It could not determine the value of bitrate')
142
143
        return Bitrate(video, audio, overall, type=_type)
144
145
146
__all__ = [
147
    'FFProbe'
148
]
149