Passed
Push — master ( 671d58...c8c24d )
by Amin
03:46
created

ffmpeg_streaming.media.StreamToFile.__init__()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 3
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
"""
2
ffmpeg_streaming.media
3
~~~~~~~~~~~~
4
5
Media object to build a stream objects
6
7
8
:copyright: (c) 2019 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 os
15
import shutil
16
import tempfile
17
18
from ffmpeg_streaming.build_commands import build_command
19
from ffmpeg_streaming.clouds import open_from_cloud, save_to_clouds
20
from ffmpeg_streaming.export_hls_playlist import export_hls_playlist
21
from ffmpeg_streaming.utiles import get_path_info, clear_tmp_file, is_url
22
from .key_info_file import generate_key_info_file
23
from .process import Process
24
from ._ffprobe import *
25
from .auto_rep import AutoRepresentation
26
27
28
def _get_paths(output, _input, clouds):
29
    is_tmp = False
30
31
    if output is not None:
32
        dirname, name = get_path_info(output)
33
    else:
34
        dirname, name = get_path_info(_input)
35
        output = _input
36
    if clouds is not None:
37
        is_tmp = True
38
        basename = os.path.basename(output)
39
        output = os.path.join(tempfile.mkdtemp(suffix='ffmpeg_streaming'), basename)
40
        dirname, name = get_path_info(output)
41
42
    return output, dirname, name, is_tmp
43
44
45
def _save_hls_master_playlist(output, master_playlist_path, dirname, name):
46
    if is_url(output):
47
        if master_playlist_path is None:
48
            raise ValueError("You must specify a path for master playlist")
49
        playlist_path = master_playlist_path
50
        manifests = dirname + "/" + name
51
    else:
52
        playlist_path = dirname + "/" + name + ".m3u8"
53
        manifests = name
54
    export_hls_playlist(playlist_path, manifests, Export.reps)
55
56
57
class Export(object):
58
    video_format = str
59
    audio_format = str
60
    _ffprobe = dict
61
    reps = list
62
    output = str
63
    _is_tmp_directory = False
64
65
    def __init__(self, filename, options):
66
        self.filename = filename
67
        self.options = options
68
69
    def __del__(self):
70
        clear_tmp_file(self.filename)
71
        if isinstance(self, HLS):
72
            clear_tmp_file(self.hls_key_info_file)
73
        if Export._is_tmp_directory:
74
            shutil.rmtree(os.path.dirname(str(Export.output)), ignore_errors=True)
75
76
    def __getattr__(self, name):
77
        def method(*args, **kwargs):
78
            # TODO: implement save and live methods in the future
79
            if name in ['save', 'live']:
80
                self.package(*args, **kwargs)
81
            else:
82
                raise AttributeError("The object has no attribute {}".format(name))
83
84
        return method
85
86
    def add_rep(self, *args):
87
        Export.reps = list(args)
88
        return self
89
90
    def auto_rep(self, heights=None, cmd='ffprobe'):
91
        Export._ffprobe = ffprobe(self.filename, cmd)
92
        Export.reps = AutoRepresentation(Export._ffprobe, heights).generate()
93
        return self
94
95
    def format(self, video, audio=None):
96
        Export.video_format = video
97
        Export.audio_format = audio
98
        return self
99
100
    def package(
101
            self,
102
            output=None,
103
            clouds=None,
104
            progress=None,
105
            cmd='ffmpeg',
106
            c_stdout=False,
107
            c_stderr=True,
108
            c_stdin=True,
109
            c_input=None,
110
            timeout=None
111
         ):
112
        Export.output, dirname, name, Export._is_tmp_directory = _get_paths(output, self.filename, clouds)
113
114
        if isinstance(self, HLS):
115
            _save_hls_master_playlist(output, self.master_playlist_path, dirname, name)
116
117
        with Process(progress, build_command(cmd, self), c_stdout, c_stderr, c_stdin) as process:
118
            p = process.run(c_input, timeout)
119
120
        save_to_clouds(clouds, dirname)
121
122
        if output is not None and clouds is not None:
123
            shutil.move(dirname, os.path.dirname(output))
124
125
        return self, p, Export._ffprobe
126
127
128
class HLS(Export):
129
130
    def __init__(self, filename, **options):
131
        self.hls_time = options.pop('hls_time', 10)
132
        self.hls_allow_cache = options.pop('hls_allow_cache', 0)
133
        self.hls_list_size = options.pop('hls_list_size', 0)
134
        self.master_playlist_path = options.pop('master_playlist_path', 0)
135
        self.hls_key_info_file = options.pop('hls_key_info_file', None)
136
        super(HLS, self).__init__(filename, options)
137
138
    def encryption(self, url, path, length=16):
139
        self.hls_key_info_file = generate_key_info_file(url, path, length)
140
        return self
141
142
143
class DASH(Export):
144
145
    def __init__(self, filename, **options):
146
        self.adaption = options.pop('adaption', None)
147
        self.init_seg_name = options.pop('init_seg_name', None)
148
        self.media_seg_name = options.pop('media_seg_name', None)
149
        super(DASH, self).__init__(filename, options)
150
151
152
class StreamToFile(Export):
153
154
    def __init__(self, filename, **options):
155
        super(StreamToFile, self).__init__(filename, options)
156
157
158
def _check_file(file):
159
    if type(file) == tuple:
160
        file = open_from_cloud(file)
161
    return file
162
163
164
def dash(file, **options):
165
    return DASH(_check_file(file), **options)
166
167
168
def hls(file, **options):
169
    return HLS(_check_file(file), **options)
170
171
172
def stream2file(file, **options):
173
    return StreamToFile(file, **options)
174
175
176
__all__ = [
177
    'dash',
178
    'hls',
179
    'stream2file'
180
]
181