Example #1
0
def test_moviepy(infile, out_dir):
    import numpy as np
    import pipi
    from moviepy.video.io.ffmpeg_reader import FFMPEG_VideoReader
    from moviepy.video.io.ffmpeg_writer import FFMPEG_VideoWriter
    chunksize = 128

    vr = FFMPEG_VideoReader(infile)
    w,h = vr.size

    chunk = np.zeros((h, w, vr.depth, chunksize), dtype=np.uint8)
    with pipi.Timer("mp read..."):
        for i in range(chunksize):

            frame = vr.read_frame()
            chunk[...,i] = frame

    vw = FFMPEG_VideoWriter(os.path.join(out_dir, "mp_ov.mkv"), (w,h), 30, codec="libx264", preset="fast", ffmpeg_params=["-crf", "0"])

    with pipi.Timer("mp write..."):
        for i in range(chunksize):
            vw.write_frame(chunk[...,i])

    vr.close()
    vw.close()
Example #2
0
def test_moviepy(infile, out_dir):
    import numpy as np
    import pipi
    from moviepy.video.io.ffmpeg_reader import FFMPEG_VideoReader
    from moviepy.video.io.ffmpeg_writer import FFMPEG_VideoWriter
    chunksize = 128

    vr = FFMPEG_VideoReader(infile)
    w,h = vr.size

    chunk = np.zeros((h, w, vr.depth, chunksize), dtype=np.uint8)
    with pipi.Timer("mp read..."):
        for i in range(chunksize):

            frame = vr.read_frame()
            chunk[...,i] = frame

    vw = FFMPEG_VideoWriter(os.path.join(out_dir, "mp_ov.mkv"), (w,h), 30, codec="libx264", preset="fast", ffmpeg_params=["-crf", "0"])

    with pipi.Timer("mp write..."):
        for i in range(chunksize):
            vw.write_frame(chunk[...,i])

    vr.close()
    vw.close()
Example #3
0
def get_video_info(video_path):
    # video_fps, video_n_frames, video_duration = video_utils.

    cap = FFMPEG_VideoReader(video_path, False)
    cap.initialize()
    fps = cap.fps
    n_frames = cap.nframes
    duration = cap.duration
    cap.close()
    del cap

    return fps, n_frames, duration
Example #4
0
def test_autorotate():
    # This test requires ffmpeg >=2.7
    video_file = 'media/ficus_vertical.mp4'
    reader = FFMPEG_VideoReader(video_file)
    assert reader.infos['video_size'] == [1920, 1080]
    assert reader.infos['video_rotation'] == 90
    assert reader.size == [1080, 1920]
    reader.close()

    reader = FFMPEG_VideoReader(video_file, ffmpeg_params=['-noautorotate'])
    assert reader.size == [1920, 1080]
    assert reader.rotation == 90
    reader.close()
Example #5
0
def video_uniform_sample_and_save_old(spf,
                                      video_path,
                                      frames_path,
                                      image_name_format,
                                      resize_type,
                                      verbose=False):
    if resize_type is not None:
        assert resize_type in ['resize', 'resize_crop', 'resize_crop_scaled']

    resize_function = None
    if resize_type == 'resize':
        resize_function = image_utils.resize_frame
    elif resize_type == 'resize_crop':
        resize_function = image_utils.resize_crop
    elif resize_type == 'resize_crop_scaled':
        resize_function = image_utils.resize_crop_scaled

    cap = FFMPEG_VideoReader(video_path, False)
    cap.initialize()
    fps = cap.fps
    n_frames = cap.nframes
    duration = cap.duration
    n_samples = int(duration / float(spf))

    # check if no samples because the video duration is less than spf
    # then at least, get 1 frame of the video
    if n_samples == 0:
        n_samples = 1

    for i in range(n_samples):
        num = i + 1
        if verbose:
            print(' ... reading frame %d/%d' % (num, n_samples))
        time_sec = i * spf
        frame = cap.get_frame(time_sec)

        if resize_type is not None:
            # resize frame to fit in the array, it's going to be used by caffe anyway
            frame = resize_function(frame)

        frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
        image_name = image_name_format % (num, )
        frame_path = os.path.join(frames_path, image_name)
        cv2.imwrite(frame_path, frame)

    # very important, or we'd have memory leakage
    cap.close()

    return fps, n_frames, duration
Example #6
0
    else:
        writer = FFMPEG_VideoWriter(arguments_strVideoOut, reader.size,
                                    reader.fps * 2)

    if exists:
        # Write frames that were already completed
        print("Re-writing processed frames...")
        printProgressBar(0, readerCont.nframes)
        for x in range(0, readerCont.nframes):
            writer.write_frame(readerCont.read_frame())
            printProgressBar(x + 1, readerCont.nframes)

        reader.skip_frames(startFrame)

        readerCont.close()

        print("Deleting temporary file(s)...")
        shutil.rmtree(tempDir)

        print("Processing resumed!")
        print("")

    totalFrames = reader.nframes
    nextFrame = reader.read_frame()
    startedTime = datetime.now()
    for x in range(startFrame, reader.nframes):
        start = datetime.now()
        firstFrame = nextFrame
        nextFrame = reader.read_frame()
        tensorInputFirst = torch.FloatTensor(
Example #7
0
class VideoFileClip(VideoClip):
    """
    A video clip originating from a movie file. For instance: ::

        >>> clip = VideoFileClip("myHolidays.mp4")
        >>> clip.close()
        >>> with VideoFileClip("myMaskVideo.avi") as clip2:
        >>>    pass  # Implicit close called by context manager.


    Parameters
    ----------

    filename:
      The name of the video file, as a string or a path-like object.
      It can have any extension supported by ffmpeg:
      .ogv, .mp4, .mpeg, .avi, .mov etc.

    has_mask:
      Set this to 'True' if there is a mask included in the videofile.
      Video files rarely contain masks, but some video codecs enable
      that. For instance if you have a MoviePy VideoClip with a mask you
      can save it to a videofile with a mask. (see also
      ``VideoClip.write_videofile`` for more details).

    audio:
      Set to `False` if the clip doesn't have any audio or if you do not
      wish to read the audio.

    target_resolution:
      Set to (desired_width, desired_height) to have ffmpeg resize the frames
      before returning them. This is much faster than streaming in high-res
      and then resizing. If either dimension is None, the frames are resized
      by keeping the existing aspect ratio.

    resize_algorithm:
      The algorithm used for resizing. Default: "bicubic", other popular
      options include "bilinear" and "fast_bilinear". For more information, see
      https://ffmpeg.org/ffmpeg-scaler.html

    fps_source:
      The fps value to collect from the metadata. Set by default to 'fps', but
      can be set to 'tbr', which may be helpful if you are finding that it is reading
      the incorrect fps from the file.

    pixel_format
      Optional: Pixel format for the video to read. If is not specified
      'rgb24' will be used as the default format unless ``has_mask`` is set
      as ``True``, then 'rgba' will be used.


    Attributes
    ----------

    filename:
      Name of the original video file.

    fps:
      Frames per second in the original file.


    Read docs for Clip() and VideoClip() for other, more generic, attributes.

    Lifetime
    --------

    Note that this creates subprocesses and locks files. If you construct one
    of these instances, you must call close() afterwards, or the subresources
    will not be cleaned up until the process ends.

    If copies are made, and close() is called on one, it may cause methods on
    the other copies to fail.

    """
    @convert_path_to_string("filename")
    def __init__(
        self,
        filename,
        decode_file=False,
        has_mask=False,
        audio=True,
        audio_buffersize=200000,
        target_resolution=None,
        resize_algorithm="bicubic",
        audio_fps=44100,
        audio_nbytes=2,
        fps_source="fps",
        pixel_format=None,
    ):

        VideoClip.__init__(self)

        # Make a reader
        if not pixel_format:
            pixel_format = "rgba" if has_mask else "rgb24"
        self.reader = FFMPEG_VideoReader(
            filename,
            decode_file=decode_file,
            pixel_format=pixel_format,
            target_resolution=target_resolution,
            resize_algo=resize_algorithm,
            fps_source=fps_source,
        )

        # Make some of the reader's attributes accessible from the clip
        self.duration = self.reader.duration
        self.end = self.reader.duration

        self.fps = self.reader.fps
        self.size = self.reader.size
        self.rotation = self.reader.rotation

        self.filename = filename

        if has_mask:

            self.make_frame = lambda t: self.reader.get_frame(t)[:, :, :3]

            def mask_make_frame(t):
                return self.reader.get_frame(t)[:, :, 3] / 255.0

            self.mask = VideoClip(is_mask=True,
                                  make_frame=mask_make_frame).with_duration(
                                      self.duration)
            self.mask.fps = self.fps

        else:

            self.make_frame = lambda t: self.reader.get_frame(t)

        # Make a reader for the audio, if any.
        if audio and self.reader.infos["audio_found"]:

            self.audio = AudioFileClip(
                filename,
                buffersize=audio_buffersize,
                fps=audio_fps,
                nbytes=audio_nbytes,
            )

    def __deepcopy__(self, memo):
        """Implements ``copy.deepcopy(clip)`` behaviour as ``copy.copy(clip)``.

        VideoFileClip class instances can't be deeply copied because the locked Thread
        of ``proc`` isn't pickleable. Without this override, calls to
        ``copy.deepcopy(clip)`` would raise a ``TypeError``:

        ```
        TypeError: cannot pickle '_thread.lock' object
        ```
        """
        return self.__copy__()

    def close(self):
        """Close the internal reader."""
        if self.reader:
            self.reader.close()
            self.reader = None

        try:
            if self.audio:
                self.audio.close()
                self.audio = None
        except AttributeError:  # pragma: no cover
            pass
Example #8
0
class VideoFileClip(VideoClip):

    """

    A video clip originating from a movie file. For instance: ::

        >>> clip = VideoFileClip("myHolidays.mp4")
        >>> clip.close()
        >>> with VideoFileClip("myMaskVideo.avi") as clip2:
        >>>    pass  # Implicit close called by contex manager.


    Parameters
    ------------

    filename:
      The name of the video file. It can have any extension supported
      by ffmpeg: .ogv, .mp4, .mpeg, .avi, .mov etc.

    has_mask:
      Set this to 'True' if there is a mask included in the videofile.
      Video files rarely contain masks, but some video codecs enable
      that. For istance if you have a MoviePy VideoClip with a mask you
      can save it to a videofile with a mask. (see also
      ``VideoClip.write_videofile`` for more details).

    audio:
      Set to `False` if the clip doesn't have any audio or if you do not
      wish to read the audio.

    target_resolution:
      Set to (desired_height, desired_width) to have ffmpeg resize the frames
      before returning them. This is much faster than streaming in high-res
      and then resizing. If either dimension is None, the frames are resized
      by keeping the existing aspect ratio.

    resize_algorithm:
      The algorithm used for resizing. Default: "bicubic", other popular
      options include "bilinear" and "fast_bilinear". For more information, see
      https://ffmpeg.org/ffmpeg-scaler.html

    fps_source:
      The fps value to collect from the metadata. Set by default to 'tbr', but
      can be set to 'fps', which may be helpful if importing slow-motion videos
      that get messed up otherwise.


    Attributes
    -----------

    filename:
      Name of the original video file.

    fps:
      Frames per second in the original file.
    
    
    Read docs for Clip() and VideoClip() for other, more generic, attributes.
    
    Lifetime
    --------
    
    Note that this creates subprocesses and locks files. If you construct one of these instances, you must call
    close() afterwards, or the subresources will not be cleaned up until the process ends.
    
    If copies are made, and close() is called on one, it may cause methods on the other copies to fail.  

    """

    def __init__(self, filename, has_mask=False,
                 audio=True, audio_buffersize = 200000,
                 target_resolution=None, resize_algorithm='bicubic',
                 audio_fps=44100, audio_nbytes=2, verbose=False,
                 fps_source='tbr'):

        VideoClip.__init__(self)

        # Make a reader
        pix_fmt= "rgba" if has_mask else "rgb24"
        self.reader = FFMPEG_VideoReader(filename, pix_fmt=pix_fmt,
                                         target_resolution=target_resolution,
                                         resize_algo=resize_algorithm,
                                         fps_source=fps_source)

        # Make some of the reader's attributes accessible from the clip
        self.duration = self.reader.duration
        self.end = self.reader.duration

        self.fps = self.reader.fps
        self.size = self.reader.size
        self.rotation = self.reader.rotation

        self.filename = self.reader.filename

        if has_mask:

            self.make_frame = lambda t: self.reader.get_frame(t)[:,:,:3]
            mask_mf =  lambda t: self.reader.get_frame(t)[:,:,3]/255.0
            self.mask = (VideoClip(ismask = True, make_frame = mask_mf)
                       .set_duration(self.duration))
            self.mask.fps = self.fps

        else:

            self.make_frame = lambda t: self.reader.get_frame(t)

        # Make a reader for the audio, if any.
        if audio and self.reader.infos['audio_found']:

            self.audio = AudioFileClip(filename,
                                       buffersize= audio_buffersize,
                                       fps = audio_fps,
                                       nbytes = audio_nbytes)

    def close(self):
        """ Close the internal reader. """
        if self.reader:
            self.reader.close()
            self.reader = None

        try:
            if self.audio:
                self.audio.close()
                self.audio = None
        except AttributeError:
            pass
    print "n_frames:", movie_reader.nframes
    # the 1st frame of the saved video can't be directly read by movie_reader.read_frame(), I don't know why
    # maybe it's a bug of anim.save, actually, if we look at the movie we get from anim.save
    # we can easilly see that the 1st frame just close very soon.
    # so I manually get it at time 0, this is just a trick, I think.
    tmp_frame = movie_reader.get_frame(0)
    [
        movie_writer.write_frame(tmp_frame)
        for _ in range(int(new_fps * play_slow_rate))
    ]
    # for the above reason, we should read (movie_reader.nframes-1) frames so that the last frame is not
    # read twice (not that get_frame(0) alread read once)
    # However, I soon figure out that it should be (movie_reader.nframes-2). The details: we have actually
    # 6 frames, but (print movie_reader.nframes) is 7. I read the first frame through movie_reader.get_frame(0)
    # then are are 5 left. So I should use movie_reader.nframes - 2. Note that in fig1_pcm_fs2.py
    # in the case of: original fps=1
    # new_fps = 24, play_slow_rate = 1.5 the result is: 1st frame last 1.8s, others 1.5s, i.e., the 1st frame
    # has more duration. This is messy.
    for i in range(movie_reader.nframes - 2):
        tmp_frame = movie_reader.read_frame()
        [
            movie_writer.write_frame(tmp_frame)
            for _ in range(int(new_fps * play_slow_rate))
        ]
        pass
    movie_reader.close()
    movie_writer.close()
    os.remove(tmp_video_name)
    # plt.show()
    pass
Example #10
0
class MovieEditor(object):
    def __init__(self,
                 input,
                 output,
                 width=None,
                 height=None,
                 log_level=FFMPEG_LOGLEVEL):
        self._reader = FFMPEG_VideoReader(input)
        self._fps = self._reader.fps
        # self.cur_frame = 1
        # self._frame = None
        self._querier = FfmpegQuerier()
        self._info = self._querier(input)
        self._duration = self._querier.duration
        self.draw_dict = {}
        self._resize = (int(width),
                        int(height)) if (width and height) else None
        self._loglevel = log_level
        self._output = output
        self._tmp_file = self._make_tmp_file(input) if self._resize else None
        self._writer = FFMPEG_VideoWriter(
            self._tmp_file if self.need_resize else output,
            size=self._reader.size,
            fps=self._reader.fps)

    @property
    def need_resize(self):
        return self._resize and list(self._resize) != list(self._reader.size)

    # for resizing
    def _make_tmp_file(self, input):
        return '%s-%s.mp4' % (input, get_time())

    def _remove_tmp_file(self):
        if os.path.exists(self._tmp_file):
            os.remove(self._tmp_file)

    # approximate frame count
    def get_total_frame(self):
        return timestamp2frame(self._duration, self._fps)

    # def seek_frame(self, index):
    #     self._reader.skip_frames(index - self.cur_frame)
    #     self._frame = self._reader.read_frame()
    #
    # def seek_timestamp(self, timestamp):
    #     index = FrameEditor.which_frame(timestamp, self._fps)
    #     self.seek_frame(index)
    #
    # def draw_anno(self, anno):
    #     if self._frame is not None:
    #         self._frame_editor.frame = self._frame
    #         self._frame_editor.draw_anno(anno)

    def draw_anno_file(self, anno_filename):
        # parse anno file
        ax = AnnoXml()
        ax.read(anno_filename)
        ax.parse()
        commands = ax.command

        fps = self._fps
        frame = self._reader.read_frame()
        self._writer.write_frame(frame)
        # total frame
        total_frame = self.get_total_frame()
        with click.progressbar(length=total_frame,
                               label='Processing...') as bar:
            # current
            frame_index = 1
            bar.update(1)
            for command in commands:
                pageid = command.pageid
                command_frame = CommandParser.get_frame_index(command, fps)
                if pageid in self.draw_dict:
                    frame_editor = self.draw_dict[pageid]
                else:
                    frame_editor = FrameEditor(fps=fps, pageid=pageid)
                    self.draw_dict[pageid] = frame_editor
                # before
                while frame_index < command_frame:
                    if not frame_editor.commands:
                        frame = self.read_frame()
                        self.write_frame(frame)
                    else:
                        frame = self.read_frame()
                        frame_editor.draw(frame)
                        self.write_frame(frame_editor.image)
                    frame_index += 1
                    bar.update(1)
                # append
                frame_editor.append_command(command)
                # current
                frame = self.read_frame()
                frame_editor.draw(frame)
                self.write_frame(frame_editor.image)
                frame_index += 1
                bar.update(1)
            # write left frames
            while frame_index < total_frame:
                self.write_frame(self.read_frame())
                frame_index += 1
                bar.update(1)
        # close stream
        self.close()
        # resize if needed
        if self.need_resize:
            self.resize()
            self._remove_tmp_file()

    def read_frame(self):
        return self._reader.read_frame()

    def write_frame(self, frame):
        # if self._resize:
        #     if not isinstance(frame, Image.Image):
        #         frame = Image.fromarray(frame.astype('uint8'))
        # Here's a bug.
        #     frame = frame.resize(self._resize, Image.ANTIALIAS)
        self._writer.write_frame(frame)

    def resize(self):
        parameters = [
            FFMPEG_FILE, '-i', self._tmp_file, '-s',
            '{w}*{h}'.format(w=self._resize[0], h=self._resize[1]),
            '-loglevel', self._loglevel, '-y', self._output
        ]

        subprocess.call(parameters)

    def close(self):
        self._reader.close()
        self._writer.close()
Example #11
0
class VideoFileClip(VideoClip):
    """

    A video clip originating from a movie file. For instance: ::

        >>> clip = VideoFileClip("myHolidays.mp4")
        >>> clip.close()
        >>> with VideoFileClip("myMaskVideo.avi") as clip2:
        >>>    pass  # Implicit close called by context manager.


    Parameters
    ------------

    filename:
      The name of the video file. It can have any extension supported
      by ffmpeg: .ogv, .mp4, .mpeg, .avi, .mov etc.

    has_mask:
      Set this to 'True' if there is a mask included in the videofile.
      Video files rarely contain masks, but some video codecs enable
      that. For istance if you have a MoviePy VideoClip with a mask you
      can save it to a videofile with a mask. (see also
      ``VideoClip.write_videofile`` for more details).

    audio:
      Set to `False` if the clip doesn't have any audio or if you do not
      wish to read the audio.

    target_resolution:
      Set to (desired_height, desired_width) to have ffmpeg resize the frames
      before returning them. This is much faster than streaming in high-res
      and then resizing. If either dimension is None, the frames are resized
      by keeping the existing aspect ratio.

    resize_algorithm:
      The algorithm used for resizing. Default: "bicubic", other popular
      options include "bilinear" and "fast_bilinear". For more information, see
      https://ffmpeg.org/ffmpeg-scaler.html

    fps_source:
      The fps value to collect from the metadata. Set by default to 'tbr', but
      can be set to 'fps', which may be helpful if importing slow-motion videos
      that get messed up otherwise.


    Attributes
    -----------

    filename:
      Name of the original video file.

    fps:
      Frames per second in the original file.


    Read docs for Clip() and VideoClip() for other, more generic, attributes.

    Life time
    --------

    Note that this creates sub-processes and locks files. If you construct one of these instances, you must call
    close() afterwards, or the sub-resources will not be cleaned up until the process ends.

    If copies are made, and close() is called on one, it may cause methods on the other copies to fail.

    """
    def __init__(self,
                 filename,
                 has_mask=False,
                 audio=True,
                 audio_buffersize=200000,
                 target_resolution=None,
                 resize_algorithm='bicubic',
                 audio_fps=44100,
                 audio_nbytes=2,
                 verbose=False,
                 fps_source='tbr'):

        VideoClip.__init__(self)

        # Make a reader
        pix_fmt = "rgba" if has_mask else "rgb24"
        self.reader = FFMPEG_VideoReader(filename,
                                         pix_fmt=pix_fmt,
                                         target_resolution=target_resolution,
                                         resize_algo=resize_algorithm,
                                         fps_source=fps_source)

        # Make some of the reader's attributes accessible from the clip
        self.duration = self.reader.duration
        self.end = self.reader.duration

        self.fps = self.reader.fps
        self.size = self.reader.size
        self.rotation = self.reader.rotation

        self.filename = self.reader.filename

        if has_mask:

            self.make_frame = lambda t: self.reader.get_frame(t)[:, :, :3]
            mask_mf = lambda t: self.reader.get_frame(t)[:, :, 3] / 255.0
            self.mask = (VideoClip(
                ismask=True, make_frame=mask_mf).set_duration(self.duration))
            self.mask.fps = self.fps

        else:

            self.make_frame = lambda t: self.reader.get_frame(t)

        # Make a reader for the audio, if any.
        if audio and self.reader.infos['audio_found']:
            self.audio = AudioFileClip(filename,
                                       buffersize=audio_buffersize,
                                       fps=audio_fps,
                                       nbytes=audio_nbytes)

    def close(self):
        """ Close the internal reader. """
        if self.reader:
            self.reader.close()
            self.reader = None

        try:
            if self.audio:
                self.audio.close()
                self.audio = None
        except AttributeError:
            pass