Ejemplo n.º 1
0
    def capture_timeline_thumbnails(self, stream_file, filename, duration,
                                    thumbnails_amount):
        """
        Capture thumbnails for timeline.
        :param stream_file: video file
        :type stream_file: bytes
        :param filename: tmp video's file name
        :type filename: str
        :param duration: video's duration
        :type duration: int
        :param thumbnails_amount: total number of thumbnails to capture
        :type thumbnails_amount: int
        :return: file stream, metadata generator
        :return: bytes, generator
        """

        path_video = create_temp_file(stream_file)
        try:
            # time period between two frames
            if thumbnails_amount == 1:
                frame_per_second = (duration - 0.05)
            else:
                frame_per_second = (duration - 0.05) / (thumbnails_amount - 1)

            # capture list frame via script capture_list_frames.sh
            path_script = os.path.dirname(
                __file__) + '/script/capture_list_frames.sh'
            # create output file path
            output_file = f"{path_video}_"
            # subprocess bash -> ffmpeg in the loop
            subprocess.run([
                path_script, path_video, output_file,
                str(frame_per_second),
                str(thumbnails_amount)
            ])
            for i in range(0, thumbnails_amount):
                thumbnail_path = f'{output_file}{i}.png'
                try:
                    # get metadata
                    thumbnail_metadata = self._get_meta(thumbnail_path)
                    thumbnail_metadata['mimetype'] = 'image/png'
                    # read binary
                    with open(thumbnail_path, "rb") as f:
                        content = f.read()
                    yield content, thumbnail_metadata
                finally:
                    # delete temp thumbnail file
                    os.remove(thumbnail_path)
        finally:
            os.remove(path_video)
Ejemplo n.º 2
0
    def get_meta(self, filestream, extension='tmp'):
        """
        Use ffmpeg tool for getting metadata of file
        :param filestream: file to get meta from
        :type filestream: bytes
        :return: metadata
        :rtype: dict
        """

        file_temp_path = create_temp_file(filestream)
        try:
            metadata = self._get_meta(file_temp_path)
        finally:
            os.remove(file_temp_path)

        return metadata
Ejemplo n.º 3
0
    def edit_video(self, stream_file, filename, trim=None, crop=None, rotate=None, scale=None):
        """
        Use ffmpeg tool for edit video
        :param stream_file: file to edit
        :type stream_file: bytes
        :param filename: filename for tmp file
        :type filename: str
        :param trim: trim editing rules
        :type trim: dict
        :param crop: crop editing rules
        :type crop: dict
        :param video_rotate: rotate degree
        :type video_rotate: int
        :param scale: width scale to
        :type scale: int
        :return:
        """

        # file extension is required by ffmpeg
        path_input = create_temp_file(stream_file, suffix=f".{filename.rsplit('.', 1)[-1]}")
        path_output = '{}_edit.{}'.format(*path_input.rsplit('.', 1))
        filter_string = ''
        try:
            # get option for trim
            trim_option = (
                '-ss', str(trim['start']),
                '-t', str(trim['end'] - trim['start']),
                '-qscale', '0',
            ) if trim else tuple()
            # crop
            # https://ffmpeg.org/ffmpeg-filters.html#crop
            if crop:
                filter_string += f'crop={crop["width"]}:{crop["height"]}:{crop["x"]}:{crop["y"]}'
            # scale
            # http://ffmpeg.org/ffmpeg-filters.html#scale
            # https://trac.ffmpeg.org/wiki/Scaling
            if scale:
                filter_string += ',' if filter_string != '' else ''
                filter_string += f"scale={scale}:-2"
            # rotate
            # https://ffmpeg.org/ffmpeg-all.html#transpose
            # 0 = 90CounterCLockwise and Vertical Flip (default)
            # 1 = 90Clockwise
            # 2 = 90CounterClockwise
            # 3 = 90Clockwise and Vertical Flip
            if rotate:
                rotate_string = ''
                if rotate == 90:
                    rotate_string = 'transpose=1'
                elif rotate == -90:
                    rotate_string = 'transpose=2'
                elif rotate == 180:
                    rotate_string = 'transpose=1,transpose=1'
                elif rotate == -180:
                    rotate_string = 'transpose=2,transpose=2'
                elif rotate == 270:
                    rotate_string = 'transpose=1,transpose=1,transpose=1'
                elif rotate == -270:
                    rotate_string = 'transpose=2,transpose=2,transpose=2'
                filter_string += ',' if filter_string != '' else ''
                filter_string += rotate_string
            # get option for filter
            filter_option = ('-filter:v', filter_string) if filter_string else tuple()
            # run ffmpeg
            if filter_option or trim_option:
                # combine trim and filter to run one time
                self._run_ffmpeg(
                    path_input=path_input,
                    path_output=path_output,
                    options=(
                        *trim_option,
                        *filter_option,
                        '-threads', str(app.config.get('FFMPEG_THREADS')),
                        '-preset', app.config.get('FFMPEG_PRESET')
                    )
                )
            content = open(path_input, 'rb+').read()
            metadata_edit_file = self._get_meta(path_input)
        finally:
            if path_input:
                os.remove(path_input)
        return content, metadata_edit_file
Ejemplo n.º 4
0
    def capture_thumbnail(self, stream_file, filename, duration, position, crop=None, rotate=0):
        """
        Use ffmpeg tool to capture video frame at a position.
        :param stream_file: video file
        :type stream_file: bytes
        :param filename: tmp video's file name
        :type filename: str
        :param duration: video's duration
        :type duration: int
        :param position: video position to capture a frame
        :type position: int
        :param crop: crop editing rules
        :type crop: dict
        :param rotate: rotate degree
        :type rotate: int
        :return: file stream, metadata
        :rtype: bytes, dict
        """

        path_video = create_temp_file(stream_file)
        try:
            # avoid the last frame, it is null
            if int(duration) <= int(position):
                position = duration - 0.1
            # create output file path
            output_file = f"{path_video}_preview_thumbnail.png"

            vfilter = ''
            if crop:
                vfilter = f'-vf crop={crop["width"]}:{crop["height"]}:{crop["x"]}:{crop["y"]}'
            if rotate:
                vfilter += ',' if vfilter else '-vf '
                transpose = f'transpose=1' if rotate > 0 else f'transpose=2'
                vfilter += ','.join([transpose] * (rotate // 90))

            try:
                # run ffmpeg command
                self._run_ffmpeg(
                    path_input=path_video,
                    path_output=output_file,
                    preoptions=('-y', '-accurate_seek'),
                    options=(
                        '-ss', str(position),
                        '-vframes', '1',
                        *shlex.split(vfilter),
                    ),
                    override=False,
                )
                # get metadata
                thumbnail_metadata = self._get_meta(output_file)
                thumbnail_metadata['mimetype'] = 'image/png'
                # read binary
                with open(output_file, "rb") as f:
                    content = f.read()
                return content, thumbnail_metadata
            finally:
                if os.path.exists(output_file):
                    # delete temp thumbnail file
                    os.remove(output_file)
        finally:
            os.remove(path_video)