1import os
2
3from moviepy.audio.io.AudioFileClip import AudioFileClip
4from moviepy.Clip import Clip
5from moviepy.video.io.ffmpeg_reader import FFMPEG_VideoReader
6from moviepy.video.VideoClip import VideoClip
7
8
9class VideoFileClip(VideoClip):
10
11    """
12
13    A video clip originating from a movie file. For instance: ::
14
15        >>> clip = VideoFileClip("myHolidays.mp4")
16        >>> clip.close()
17        >>> with VideoFileClip("myMaskVideo.avi") as clip2:
18        >>>    pass  # Implicit close called by context manager.
19
20
21    Parameters
22    ------------
23
24    filename:
25      The name of the video file. It can have any extension supported
26      by ffmpeg: .ogv, .mp4, .mpeg, .avi, .mov etc.
27
28    has_mask:
29      Set this to 'True' if there is a mask included in the videofile.
30      Video files rarely contain masks, but some video codecs enable
31      that. For istance if you have a MoviePy VideoClip with a mask you
32      can save it to a videofile with a mask. (see also
33      ``VideoClip.write_videofile`` for more details).
34
35    audio:
36      Set to `False` if the clip doesn't have any audio or if you do not
37      wish to read the audio.
38
39    target_resolution:
40      Set to (desired_height, desired_width) to have ffmpeg resize the frames
41      before returning them. This is much faster than streaming in high-res
42      and then resizing. If either dimension is None, the frames are resized
43      by keeping the existing aspect ratio.
44
45    resize_algorithm:
46      The algorithm used for resizing. Default: "bicubic", other popular
47      options include "bilinear" and "fast_bilinear". For more information, see
48      https://ffmpeg.org/ffmpeg-scaler.html
49
50    fps_source:
51      The fps value to collect from the metadata. Set by default to 'tbr', but
52      can be set to 'fps', which may be helpful if importing slow-motion videos
53      that get messed up otherwise.
54
55
56    Attributes
57    -----------
58
59    filename:
60      Name of the original video file.
61
62    fps:
63      Frames per second in the original file.
64
65
66    Read docs for Clip() and VideoClip() for other, more generic, attributes.
67
68    Lifetime
69    --------
70
71    Note that this creates subprocesses and locks files. If you construct one of these instances, you must call
72    close() afterwards, or the subresources will not be cleaned up until the process ends.
73
74    If copies are made, and close() is called on one, it may cause methods on the other copies to fail.
75
76    """
77
78    def __init__(self, filename, has_mask=False,
79                 audio=True, audio_buffersize=200000,
80                 target_resolution=None, resize_algorithm='bicubic',
81                 audio_fps=44100, audio_nbytes=2, verbose=False,
82                 fps_source='tbr'):
83
84        VideoClip.__init__(self)
85
86        # Make a reader
87        pix_fmt = "rgba" if has_mask else "rgb24"
88        self.reader = FFMPEG_VideoReader(filename, pix_fmt=pix_fmt,
89                                         target_resolution=target_resolution,
90                                         resize_algo=resize_algorithm,
91                                         fps_source=fps_source)
92
93        # Make some of the reader's attributes accessible from the clip
94        self.duration = self.reader.duration
95        self.end = self.reader.duration
96
97        self.fps = self.reader.fps
98        self.size = self.reader.size
99        self.rotation = self.reader.rotation
100
101        self.filename = self.reader.filename
102
103        if has_mask:
104
105            self.make_frame = lambda t: self.reader.get_frame(t)[:,:,:3]
106            mask_mf = lambda t: self.reader.get_frame(t)[:,:,3]/255.0
107            self.mask = (VideoClip(ismask=True, make_frame=mask_mf)
108                         .set_duration(self.duration))
109            self.mask.fps = self.fps
110
111        else:
112
113            self.make_frame = lambda t: self.reader.get_frame(t)
114
115        # Make a reader for the audio, if any.
116        if audio and self.reader.infos['audio_found']:
117
118            self.audio = AudioFileClip(filename,
119                                       buffersize=audio_buffersize,
120                                       fps=audio_fps,
121                                       nbytes=audio_nbytes)
122
123    def close(self):
124        """ Close the internal reader. """
125        if self.reader:
126            self.reader.close()
127            self.reader = None
128
129        try:
130            if self.audio:
131                self.audio.close()
132                self.audio = None
133        except AttributeError:
134            pass
135