Exemplo n.º 1
0
    def run(self):
        _file_list = self.file_prepare()
        threshold = input("请输入画面阈值(选择区间[10, 90],如无输入则默认27.5):")
        if not threshold:
            threshold = self.threshold_default

        crf = input("请输入crf值(选择区间[1, 51],如无输入则默认20):")
        if not crf:
            crf = self.crf_default

        for key in _file_list:
            scenes = self.find_scenes(key, threshold)
            print(scenes)
            file_path, full_name = os.path.split(key)
            f_name, ext = os.path.splitext(full_name)
            split_video_ffmpeg(
                [key],
                scenes,
                "$VIDEO_NAME - Scene $SCENE_NUMBER.mp4",
                self.output_dir + "/" + f_name,
                arg_override='-c:v libx264 -preset slow -crf ' + str(crf) + ' -c:a aac',
                hide_progress=False,
                suppress_output=False
            )

        print("处理完毕~")
Exemplo n.º 2
0
def find_scenes(video_path, threshold=30.0):
    # Create our video & scene managers, then add the detector.
    video_manager = VideoManager([video_path])
    scene_manager = SceneManager()
    scene_manager.add_detector(ContentDetector(threshold=threshold))

    # Improve processing speed by downscaling before processing.
    video_manager.set_downscale_factor()

    # Start the video manager and perform the scene detection.
    video_manager.start()
    time = scene_manager.detect_scenes(frame_source=video_manager)

    # Each returned scene is a tuple of the (start, end) timecode.

    times = scene_manager.get_scene_list(time)

    video_splitter.split_video_ffmpeg(
        video_path,
        times,
        '$VIDEO_NAME - Scene $SCENE_NUMBER',
        video_path,
        arg_override='-c:v libx264 -preset fast -crf 21 -c:a aac',
        hide_progress=False,
        suppress_output=False)
Exemplo n.º 3
0
def make_elements(video_path, video_name, save_dir):
    # type: (str) -> List[Tuple[FrameTimecode, FrameTimecode]]
    video_manager = VideoManager([video_path])
    stats_manager = StatsManager()
    # Construct our SceneManager and pass it our StatsManager.
    scene_manager = SceneManager(stats_manager)

    # Add ContentDetector algorithm (each detector's constructor
    # takes detector options, e.g. threshold).
    scene_manager.add_detector(ContentDetector(threshold=threshold))
    base_timecode = video_manager.get_base_timecode()

    # We save our stats file to {VIDEO_PATH}.stats.csv.
    stats_file_path = 'stats/%s.stats.csv' % video_name

    scene_list = []

    try:
        # If stats file exists, load it.
        if os.path.exists(stats_file_path):
            # Read stats from CSV file opened in read mode:
            with open(stats_file_path, 'r') as stats_file:
                stats_manager.load_from_csv(stats_file, base_timecode)

        # Set downscale factor to improve processing speed.
        video_manager.set_downscale_factor()

        # Start video_manager.
        video_manager.start()

        # Perform scene detection on video_manager.
        scene_manager.detect_scenes(frame_source=video_manager)

        # Obtain list of detected scenes.
        scene_list = scene_manager.get_scene_list(base_timecode)
        # Each scene is a tuple of (start, end) FrameTimecodes.

    finally:
        video_manager.release()

    video_dir = os.path.join(save_dir, video_name)
    if not os.path.exists(video_dir):
        os.makedirs(video_dir)

    split_video_ffmpeg([video_path], scene_list, os.path.join(video_dir,"${VIDEO_NAME}-${SCENE_NUMBER}.mp4"), video_name)
Exemplo n.º 4
0
def chunk_videos(vid_paths):
    """Chunks videos into different scenes based on their content for later processing."""

    for vp in vid_paths:
        try:
            # Setup the different managers for chunking the scenes.
            video_manager = VideoManager([str(vp)])
            stats_manager = StatsManager()
            scene_manager = SceneManager(stats_manager)

            # Add ContentDetector algorithm (constructor takes detector options like threshold).
            scene_manager.add_detector(ContentDetector())
            base_timecode = video_manager.get_base_timecode()

            # Set downscale factor to improve processing speed (no args means default).
            video_manager.set_downscale_factor()

            # Set the duration to be however long the video is and start the video manager.
            video_manager.set_duration()
            video_manager.start()

            # Perform scene detection on video_manager and grab the scenes.
            scene_manager.detect_scenes(frame_source=video_manager)
            scene_list = scene_manager.get_scene_list(base_timecode)

            # If the output dir of the chunked videos does not exist, create it.
            if not (vp.parent / "chunks").exists():
                (vp.parent / "chunks").mkdir()

            # Split the video into chunks based on the scene list and save to the "chunks" folder.
            split_video_ffmpeg(
                [vp],
                scene_list,
                str(vp.parent / "chunks/$VIDEO_NAME-$SCENE_NUMBER.mp4"),
                "chunk"  #, arg_override = args
            )
            with open("stats.csv", 'w') as stats_file:
                stats_manager.save_to_csv(stats_file, base_timecode)
        finally:
            # Close out the video_manager.
            video_manager.release()
Exemplo n.º 5
0
    def process_input(self):
        # type: () -> None
        """ Process Input: Processes input video(s) and generates output as per CLI commands.

        Run after all command line options/sub-commands have been parsed.
        """
        logging.debug('Processing input...')
        if not self.options_processed:
            logging.debug(
                'Skipping processing, CLI options were not parsed successfully.'
            )
            return
        self.check_input_open()
        if not self.scene_manager.get_num_detectors() > 0:
            logging.error(
                'No scene detectors specified (detect-content, detect-threshold, etc...),\n'
                '  or failed to process all command line arguments.')
            return

        # Handle scene detection commands (detect-content, detect-threshold, etc...).
        self.video_manager.start()
        base_timecode = self.video_manager.get_base_timecode()

        start_time = time.time()
        logging.info('Detecting scenes...')

        num_frames = self.scene_manager.detect_scenes(
            frame_source=self.video_manager,
            frame_skip=self.frame_skip,
            show_progress=not self.quiet_mode)

        duration = time.time() - start_time
        logging.info('Processed %d frames in %.1f seconds (average %.2f FPS).',
                     num_frames, duration,
                     float(num_frames) / duration)

        # Handle -s/--statsfile option.
        if self.stats_file_path is not None:
            if self.stats_manager.is_save_required():
                with open(self.stats_file_path, 'wt') as stats_file:
                    logging.info('Saving frame metrics to stats file: %s',
                                 os.path.basename(self.stats_file_path))
                    self.stats_manager.save_to_csv(stats_file, base_timecode)
            else:
                logging.debug(
                    'No frame metrics updated, skipping update of the stats file.'
                )

        # Get list of detected cuts and scenes from the SceneManager to generate the required output
        # files with based on the given commands (list-scenes, split-video, save-images, etc...).
        cut_list = self.scene_manager.get_cut_list(base_timecode)
        scene_list = self.scene_manager.get_scene_list(base_timecode)
        video_paths = self.video_manager.get_video_paths()
        video_name = os.path.basename(video_paths[0])
        if video_name.rfind('.') >= 0:
            video_name = video_name[:video_name.rfind('.')]

        # Ensure we don't divide by zero.
        if scene_list:
            logging.info(
                'Detected %d scenes, average shot length %.1f seconds.',
                len(scene_list),
                sum([(end_time - start_time).get_seconds()
                     for start_time, end_time in scene_list]) /
                float(len(scene_list)))
        else:
            logging.info('No scenes detected.')

        # Handle list-scenes command.
        if self.scene_list_output:
            scene_list_filename = Template(
                self.scene_list_name_format).safe_substitute(
                    VIDEO_NAME=video_name)
            if not scene_list_filename.lower().endswith('.csv'):
                scene_list_filename += '.csv'
            scene_list_path = get_and_create_path(
                scene_list_filename,
                self.scene_list_directory if self.scene_list_directory
                is not None else self.output_directory)
            logging.info('Writing scene list to CSV file:\n  %s',
                         scene_list_path)
            with open(scene_list_path, 'wt') as scene_list_file:
                write_scene_list(scene_list_file, scene_list, cut_list)
        # Handle `list-scenes`.
        if self.print_scene_list:
            logging.info(
                """Scene List:
-----------------------------------------------------------------------
 | Scene # | Start Frame |  Start Time  |  End Frame  |   End Time   |
-----------------------------------------------------------------------
%s
-----------------------------------------------------------------------
""", '\n'.join([
                    ' |  %5d  | %11d | %s | %11d | %s |' %
                    (i + 1, start_time.get_frames(), start_time.get_timecode(),
                     end_time.get_frames(), end_time.get_timecode())
                    for i, (start_time, end_time) in enumerate(scene_list)
                ]))

        if cut_list:
            logging.info('Comma-separated timecode list:\n  %s',
                         ','.join([cut.get_timecode() for cut in cut_list]))

        # Handle save-images command.
        if self.save_images:
            self._generate_images(
                scene_list=scene_list,
                video_name=video_name,
                image_name_template=self.image_name_format,
                output_dir=self.image_directory,
                downscale_factor=self.video_manager.get_downscale_factor())

        # Handle export-html command.
        if self.export_html:
            html_filename = Template(
                self.html_name_format).safe_substitute(VIDEO_NAME=video_name)
            if not html_filename.lower().endswith('.html'):
                html_filename += '.html'
            html_path = get_and_create_path(
                html_filename, self.image_directory
                if self.image_directory is not None else self.output_directory)
            logging.info('Exporting to html file:\n %s:', html_path)
            if not self.html_include_images:
                self.image_filenames = None
            write_scene_list_html(html_path,
                                  scene_list,
                                  cut_list,
                                  image_filenames=self.image_filenames,
                                  image_width=self.image_width,
                                  image_height=self.image_height)

        # Handle split-video command.
        if self.split_video:
            # Add proper extension to filename template if required.
            dot_pos = self.split_name_format.rfind('.')
            if self.split_mkvmerge and not self.split_name_format.endswith(
                    '.mkv'):
                self.split_name_format += '.mkv'
            # Don't add if we find an extension between 2 and 4 characters
            elif not (dot_pos >= 0) or (dot_pos >= 0
                                        and not ((len(self.split_name_format) -
                                                  (dot_pos + 1) <= 4 >= 2))):
                self.split_name_format += '.mp4'

            output_file_prefix = get_and_create_path(
                self.split_name_format, self.split_directory
                if self.split_directory is not None else self.output_directory)
            mkvmerge_available = is_mkvmerge_available()
            ffmpeg_available = is_ffmpeg_available()
            if mkvmerge_available and (self.split_mkvmerge
                                       or not ffmpeg_available):
                if not self.split_mkvmerge:
                    logging.warning(
                        'ffmpeg not found, falling back to fast copy mode (split-video -c/--copy).'
                    )
                split_video_mkvmerge(video_paths,
                                     scene_list,
                                     output_file_prefix,
                                     video_name,
                                     suppress_output=self.quiet_mode
                                     or self.split_quiet)
            elif ffmpeg_available:
                if self.split_mkvmerge:
                    logging.warning(
                        'mkvmerge not found, falling back to normal splitting'
                        ' mode (split-video).')
                split_video_ffmpeg(video_paths,
                                   scene_list,
                                   output_file_prefix,
                                   video_name,
                                   arg_override=self.split_args,
                                   hide_progress=self.quiet_mode,
                                   suppress_output=self.quiet_mode
                                   or self.split_quiet)
            else:
                if not (mkvmerge_available or ffmpeg_available):
                    error_strs = [
                        "ffmpeg/mkvmerge is required for split-video [-c/--copy]."
                    ]
                else:
                    error_strs = [
                        "{EXTERN_TOOL} is required for split-video{EXTRA_ARGS}."
                        .format(EXTERN_TOOL='mkvmerge'
                                if self.split_mkvmerge else 'ffmpeg',
                                EXTRA_ARGS=' -c/--copy'
                                if self.split_mkvmerge else '')
                    ]
                error_strs += [
                    "Install one of the above tools to enable the split-video command."
                ]
                error_str = '\n'.join(error_strs)
                logging.debug(error_str)
                raise click.BadParameter(error_str, param_hint='split-video')
            if scene_list:
                logging.info(
                    'Video splitting completed, individual scenes written to disk.'
                )
Exemplo n.º 6
0
    def process_input(self):
        # type: () -> None
        """ Process Input: Processes input video(s) and generates output as per CLI commands.

        Run after all command line options/sub-commands have been parsed.
        """
        self.logger.debug('Processing input...')
        if not self.options_processed:
            self.logger.debug(
                'Skipping processing, CLI options were not parsed successfully.'
            )
            return
        self.check_input_open()
        assert self.scene_manager.get_num_detectors() >= 0
        if self.scene_manager.get_num_detectors() == 0:
            self.logger.error(
                'No scene detectors specified (detect-content, detect-threshold, etc...),\n'
                ' or failed to process all command line arguments.')
            return

        # Display a warning if the video codec type seems unsupported (#86).
        if int(abs(self.video_manager.get(cv2.CAP_PROP_FOURCC))) == 0:
            self.logger.error(
                'Video codec detection failed, output may be incorrect.\nThis could be caused'
                ' by using an outdated version of OpenCV, or using codecs that currently are'
                ' not well supported (e.g. VP9).\n'
                'As a workaround, consider re-encoding the source material before processing.\n'
                'For details, see https://github.com/Breakthrough/PySceneDetect/issues/86'
            )

        # Handle scene detection commands (detect-content, detect-threshold, etc...).
        self.video_manager.start()

        start_time = time.time()
        self.logger.info('Detecting scenes...')

        num_frames = self.scene_manager.detect_scenes(
            frame_source=self.video_manager,
            frame_skip=self.frame_skip,
            show_progress=not self.quiet_mode)

        # Handle case where video fails with multiple audio tracks (#179).
        # TODO: Using a different video backend as per #213 may also resolve this issue,
        # as well as numerous other timing related issues.
        if num_frames <= 0:
            self.logger.critical(
                'Failed to read any frames from video file. This could be caused'
                ' by the video having multiple audio tracks. If so, please try'
                ' removing the audio tracks or muxing to mkv via:\n'
                '      ffmpeg -i input.mp4 -c copy -an output.mp4\n'
                'or:\n'
                '      mkvmerge -o output.mkv input.mp4\n'
                'For details, see https://pyscenedetect.readthedocs.io/en/latest/faq/'
            )
            return

        duration = time.time() - start_time
        self.logger.info(
            'Processed %d frames in %.1f seconds (average %.2f FPS).',
            num_frames, duration,
            float(num_frames) / duration)

        # Handle -s/--statsfile option.
        if self.stats_file_path is not None:
            if self.stats_manager.is_save_required():
                with open(self.stats_file_path, 'wt') as stats_file:
                    self.logger.info('Saving frame metrics to stats file: %s',
                                     os.path.basename(self.stats_file_path))
                    base_timecode = self.video_manager.get_base_timecode()
                    self.stats_manager.save_to_csv(stats_file, base_timecode)
            else:
                self.logger.debug(
                    'No frame metrics updated, skipping update of the stats file.'
                )

        # Get list of detected cuts and scenes from the SceneManager to generate the required output
        # files with based on the given commands (list-scenes, split-video, save-images, etc...).
        cut_list = self.scene_manager.get_cut_list()
        scene_list = self.scene_manager.get_scene_list()

        # Handle --drop-short-scenes.
        if self.drop_short_scenes and self.min_scene_len > 0:
            scene_list = [
                s for s in scene_list if (s[1] - s[0]) >= self.min_scene_len
            ]

        video_paths = self.video_manager.get_video_paths()
        video_name = self.video_manager.get_video_name()

        if scene_list:  # Ensure we don't divide by zero.
            self.logger.info(
                'Detected %d scenes, average shot length %.1f seconds.',
                len(scene_list),
                sum([(end_time - start_time).get_seconds()
                     for start_time, end_time in scene_list]) /
                float(len(scene_list)))
        else:
            self.logger.info('No scenes detected.')

        # Handle list-scenes command.
        if self.scene_list_output:
            scene_list_filename = Template(
                self.scene_list_name_format).safe_substitute(
                    VIDEO_NAME=video_name)
            if not scene_list_filename.lower().endswith('.csv'):
                scene_list_filename += '.csv'
            scene_list_path = get_and_create_path(
                scene_list_filename,
                self.scene_list_directory if self.scene_list_directory
                is not None else self.output_directory)
            self.logger.info('Writing scene list to CSV file:\n  %s',
                             scene_list_path)
            with open(scene_list_path, 'wt') as scene_list_file:
                write_scene_list(output_csv_file=scene_list_file,
                                 scene_list=scene_list,
                                 include_cut_list=not self.skip_cuts,
                                 cut_list=cut_list)

        if self.print_scene_list:
            self.logger.info(
                """Scene List:
-----------------------------------------------------------------------
 | Scene # | Start Frame |  Start Time  |  End Frame  |   End Time   |
-----------------------------------------------------------------------
%s
-----------------------------------------------------------------------
""", '\n'.join([
                    ' |  %5d  | %11d | %s | %11d | %s |' %
                    (i + 1, start_time.get_frames(), start_time.get_timecode(),
                     end_time.get_frames(), end_time.get_timecode())
                    for i, (start_time, end_time) in enumerate(scene_list)
                ]))

        if cut_list:
            self.logger.info(
                'Comma-separated timecode list:\n  %s',
                ','.join([cut.get_timecode() for cut in cut_list]))

        # Handle save-images command.

        if self.save_images:
            image_output_dir = self.output_directory
            if self.image_directory is not None:
                image_output_dir = self.image_directory

            image_filenames = save_images(
                scene_list=scene_list,
                video_manager=self.video_manager,
                num_images=self.num_images,
                frame_margin=self.frame_margin,
                image_extension=self.image_extension,
                encoder_param=self.image_param,
                image_name_template=self.image_name_format,
                output_dir=image_output_dir,
                show_progress=not self.quiet_mode,
                scale=self.scale,
                height=self.height,
                width=self.width)

        # Handle export-html command.
        if self.export_html:
            html_filename = Template(
                self.html_name_format).safe_substitute(VIDEO_NAME=video_name)
            if not html_filename.lower().endswith('.html'):
                html_filename += '.html'
            html_path = get_and_create_path(
                html_filename, self.image_directory
                if self.image_directory is not None else self.output_directory)
            self.logger.info('Exporting to html file:\n %s:', html_path)
            if not self.html_include_images:
                image_filenames = None
            write_scene_list_html(html_path,
                                  scene_list,
                                  cut_list,
                                  image_filenames=image_filenames,
                                  image_width=self.image_width,
                                  image_height=self.image_height)

        # Handle split-video command.
        if self.split_video:
            output_path_template = self.split_name_format
            # Add proper extension to filename template if required.
            dot_pos = output_path_template.rfind('.')
            extension_length = 0 if dot_pos < 0 else len(
                output_path_template) - (dot_pos + 1)
            # If using mkvmerge, force extension to .mkv.
            if self.split_mkvmerge and not output_path_template.endswith(
                    '.mkv'):
                output_path_template += '.mkv'
            # Otherwise, if using ffmpeg, only add an extension if one doesn't exist.
            elif not 2 <= extension_length <= 4:
                output_path_template += '.mp4'
            output_path_template = get_and_create_path(
                output_path_template, self.split_directory
                if self.split_directory is not None else self.output_directory)
            # Ensure the appropriate tool is available before handling split-video.
            check_split_video_requirements(self.split_mkvmerge)
            if self.split_mkvmerge:
                split_video_mkvmerge(video_paths,
                                     scene_list,
                                     output_path_template,
                                     video_name,
                                     suppress_output=self.quiet_mode
                                     or self.split_quiet)
            else:
                split_video_ffmpeg(video_paths,
                                   scene_list,
                                   output_path_template,
                                   video_name,
                                   arg_override=self.split_args,
                                   hide_progress=self.quiet_mode,
                                   suppress_output=self.quiet_mode
                                   or self.split_quiet)
            if scene_list:
                self.logger.info(
                    'Video splitting completed, individual scenes written to disk.'
                )
Exemplo n.º 7
0
def find_scenes(video_path):
    start_time = time.time()
    print("Analyzing video " + video_path)

    # type: (str) -> List[Tuple[FrameTimecode, FrameTimecode]]
    video_manager = VideoManager([video_path])
    stats_manager = StatsManager()

    # Pass StatsManager to SceneManager to accelerate computing time
    scene_manager = SceneManager(stats_manager)

    # Add ContentDetector algorithm (each detector's constructor
    # takes detector options, e.g. threshold).
    scene_manager.add_detector(ContentDetector())
    base_timecode = video_manager.get_base_timecode()

    # We save our stats file to {VIDEO_PATH}.stats.csv.
    stats_file_path = '%s.stats.csv' % (video_path)

    scene_list = []

    folder = os.path.splitext(video_path)[0]

    if os.path.exists(folder):
        print(
            '--- STOP : The folder for this video already exists, it is probably already split.'
        )

    else:
        try:
            # If stats file exists, load it.
            if os.path.exists(stats_file_path):
                # Read stats from CSV file opened in read mode:
                with open(stats_file_path, 'r') as stats_file:
                    stats_manager.load_from_csv(stats_file, base_timecode)

            if video_splitter.is_ffmpeg_available():
                # Set downscale factor to improve processing speed.
                video_manager.set_downscale_factor()

                # Start video_manager.
                video_manager.start()

                # Perform scene detection on video_manager.
                scene_manager.detect_scenes(frame_source=video_manager)

                # Obtain list of detected scenes.
                scene_list = scene_manager.get_scene_list(base_timecode)
                # Each scene is a tuple of (start, end) FrameTimecodes.

                print('%s scenes obtained' % len(scene_list))

                if len(scene_list) > 0:
                    # STATISTICS : Store scenes length
                    with open(FILE_SCENE_LENGH, 'a') as myfile:
                        for i, scene in enumerate(scene_list):
                            myfile.write(
                                '%s, %d, %f\n' %
                                (os.path.splitext(
                                    os.path.basename(video_path))[0],
                                 scene[1].get_frames() - scene[0].get_frames(),
                                 (scene[1] - scene[0]).get_seconds()))

                    # STATISTICS : Store number of scenes
                    with open(FILE_SCENE_NUMBER, 'a') as myfile:
                        myfile.write('%s,%d\n' % (os.path.splitext(
                            os.path.basename(video_path))[0], len(scene_list)))

                    # Split the video
                    print('Splitting the video. Put scenes in %s/%s' %
                          (folder, VIDEO_SPLIT_TEMPLATE))
                    os.mkdir(folder)
                    video_splitter.split_video_ffmpeg(
                        [video_path],
                        scene_list,
                        folder + "/" + VIDEO_SPLIT_TEMPLATE + ".mp4",
                        os.path.basename(folder),
                        suppress_output=True)

                print("-- Finished video splitting in {:.2f}s --".format(
                    time.time() - start_time))
            else:
                print(
                    'Ffmpeg is not installed on your computer. Please install it before running this code'
                )

        finally:
            video_manager.release()

    return scene_list
Exemplo n.º 8
0
    def process_input(self):
        # type: () -> None
        """ Process Input: Processes input video(s) and generates output as per CLI commands.
        
        Run after all command line options/sub-commands have been parsed.
        """
        logging.debug('Processing input...')
        if not self.options_processed:
            logging.debug(
                'Skipping processing, CLI options were not parsed successfully.'
            )
            return
        self.check_input_open()
        if not self.scene_manager.get_num_detectors() > 0:
            logging.error(
                'No scene detectors specified (detect-content, detect-threshold, etc...).'
            )
            return

        # Handle scene detection commands (detect-content, detect-threshold, etc...).
        self.video_manager.start()
        base_timecode = self.video_manager.get_base_timecode()

        start_time = time.time()
        logging.info('Detecting scenes...')

        num_frames = self.scene_manager.detect_scenes(
            frame_source=self.video_manager,
            start_time=self.start_frame,
            frame_skip=self.frame_skip,
            show_progress=not self.quiet_mode)

        duration = time.time() - start_time
        logging.info('Processed %d frames in %.1f seconds (average %.2f FPS).',
                     num_frames, duration,
                     float(num_frames) / duration)

        # Handle -s/--statsfile option.
        if self.stats_file_path is not None:
            if self.stats_manager.is_save_required():
                with open(self.stats_file_path, 'wt') as stats_file:
                    logging.info('Saving frame metrics to stats file: %s',
                                 os.path.basename(self.stats_file_path))
                    self.stats_manager.save_to_csv(stats_file, base_timecode)
            else:
                logging.debug(
                    'No frame metrics updated, skipping update of the stats file.'
                )

        # Get list of detected cuts and scenes from the SceneManager to generate the required output
        # files with based on the given commands (list-scenes, split-video, save-images, etc...).
        cut_list = self.scene_manager.get_cut_list(base_timecode)
        scene_list = self.scene_manager.get_scene_list(base_timecode)
        video_paths = self.video_manager.get_video_paths()
        video_name = os.path.basename(video_paths[0])
        if video_name.rfind('.') >= 0:
            video_name = video_name[:video_name.rfind('.')]

        # Handle list-scenes command.
        # Handle `list-scenes -o`.
        if self.scene_list_path is not None:
            with open(self.scene_list_path, 'wt') as scene_list_file:
                write_scene_list(scene_list_file, cut_list, scene_list)
        # Handle `list-scenes`.
        list_length = len(scene_list) if len(scene_list) else 1
        logging.info(
            'Detected %d scenes, average shot length %.1f seconds.',
            list_length,
            sum([(end_time - start_time).get_seconds()
                 for start_time, end_time in scene_list]) / float(list_length))
        if self.print_scene_list:
            logging.info(
                """ Scene List:
-----------------------------------------------------------------------
 | Scene # | Start Frame |  Start Time  |  End Frame  |   End Time   |
-----------------------------------------------------------------------
%s
-----------------------------------------------------------------------
""", '\n'.join([
                    ' |  %5d  | %11d | %s | %11d | %s |' %
                    (i + 1, start_time.get_frames(), start_time.get_timecode(),
                     end_time.get_frames(), end_time.get_timecode())
                    for i, (start_time, end_time) in enumerate(scene_list)
                ]))

        if cut_list:
            logging.info('Comma-separated timecode list:\n  %s',
                         ','.join([cut.get_timecode() for cut in cut_list]))

        # Handle save-images command.
        if self.save_images:
            self._generate_images(scene_list=scene_list,
                                  image_prefix=video_name,
                                  output_dir=self.image_directory)

        # Handle split-video command.
        if self.split_video:
            output_file_name = self.get_output_file_path(
                video_name, output_dir=self.split_directory)
            mkvmerge_available = is_mkvmerge_available()
            ffmpeg_available = is_ffmpeg_available()
            if mkvmerge_available and (self.split_mkvmerge
                                       or not ffmpeg_available):
                if not self.split_mkvmerge:
                    logging.info('ffmpeg not found.')
                logging.info('Splitting input video%s using mkvmerge...',
                             's' if len(video_paths) > 1 else '')
                split_video_mkvmerge(video_paths,
                                     scene_list,
                                     output_file_name,
                                     suppress_output=self.quiet_mode
                                     or self.split_quiet)
            elif ffmpeg_available:
                logging.info('Splitting input video%s using ffmpeg...',
                             's' if len(video_paths) > 1 else '')
                split_video_ffmpeg(video_paths,
                                   scene_list,
                                   output_file_name,
                                   arg_override=self.split_args,
                                   hide_progress=self.quiet_mode
                                   or self.split_quiet,
                                   suppress_output=self.quiet_mode
                                   or self.split_quiet)
            else:
                error_strs = [
                    "ffmpeg/mkvmerge is required for video splitting.",
                    "Install one of the above tools to enable the split-video command."
                ]
                error_str = '\n'.join(error_strs)
                logging.debug(error_str)
                raise click.BadParameter(error_str, param_hint='split-video')

            logging.info(
                'Video splitting completed, individual scenes written to disk.'
            )
Exemplo n.º 9
0
def make_dataset(video_path, video_name, timecodes, save_dir):
    # type: (str) -> List[Tuple[FrameTimecode, FrameTimecode]]
    video_manager = VideoManager([video_path])
    stats_manager = StatsManager()
    # Construct our SceneManager and pass it our StatsManager.
    scene_manager = SceneManager(stats_manager)

    # Add ContentDetector algorithm (each detector's constructor
    # takes detector options, e.g. threshold).
    scene_manager.add_detector(ContentDetector())
    base_timecode = video_manager.get_base_timecode()

    # We save our stats file to {VIDEO_PATH}.stats.csv.
    stats_file_path = 'stats/%s.stats.csv' % video_name

    scene_list = []

    try:
        # If stats file exists, load it.
        if os.path.exists(stats_file_path):
            # Read stats from CSV file opened in read mode:
            with open(stats_file_path, 'r') as stats_file:
                stats_manager.load_from_csv(stats_file, base_timecode)

        # Set downscale factor to improve processing speed.
        video_manager.set_downscale_factor()

        # Start video_manager.
        video_manager.start()

        # Perform scene detection on video_manager.
        scene_manager.detect_scenes(frame_source=video_manager)

        # We only write to the stats file if a save is required:
        if stats_manager.is_save_required():
            with open(stats_file_path, 'w') as stats_file:
                stats_manager.save_to_csv(stats_file, base_timecode)

        start_timecode = ""
        start_content_val = 0
        end_timecode = ""
        end_content_val = 0
        metric_keys = sorted(
            list(
                stats_manager._registered_metrics.union(
                    stats_manager._loaded_metrics)))
        frame_keys = sorted(stats_manager._frame_metrics.keys())
        for frame_key in frame_keys:
            frame_timecode = base_timecode + frame_key
            timecode = frame_timecode.get_timecode()
            if timecode > timecodes[0] and timecode < timecodes[1]:
                content_val = stats_manager.get_metrics(
                    frame_key, metric_keys)[0]
                if start_content_val < content_val:
                    start_content_val = content_val
                    start_timecode = timecode
            if timecode > timecodes[2] and timecode < timecodes[3]:
                content_val = stats_manager.get_metrics(
                    frame_key, metric_keys)[0]
                if end_content_val < content_val:
                    end_content_val = content_val
                    end_timecode = timecode
        threshold = min(start_content_val, end_content_val)

        print(f"Start Time: {start_timecode}, End Time: {end_timecode}")

    finally:
        video_manager.release()

    video_manager = VideoManager([video_path])
    stats_manager = StatsManager()
    scene_manager = SceneManager(stats_manager)
    scene_manager.add_detector(ContentDetector(threshold=threshold))
    base_timecode = video_manager.get_base_timecode()

    scene_list = []

    try:
        # If stats file exists, load it.
        if os.path.exists(stats_file_path):
            # Read stats from CSV file opened in read mode:
            with open(stats_file_path, 'r') as stats_file:
                stats_manager.load_from_csv(stats_file, base_timecode)

        # Set downscale factor to improve processing speed.
        video_manager.set_downscale_factor()

        # Start video_manager.
        video_manager.start()

        # Perform scene detection on video_manager.
        scene_manager.detect_scenes(frame_source=video_manager)

        # Obtain list of detected scenes.
        scene_list = scene_manager.get_scene_list(base_timecode)
        # Each scene is a tuple of (start, end) FrameTimecodes.

        start_video_num = 0
        end_video_num = 0
        for i, scene in enumerate(scene_list):
            if scene[0].get_timecode(
            ) >= start_timecode and start_video_num == 0:
                start_video_num = i
                print(f"start video: {start_video_num}")
            if scene[1].get_timecode() >= end_timecode and end_video_num == 0:
                end_video_num = i
                print(f"end video: {end_video_num}")

    finally:
        video_manager.release()

    video_dir = os.path.join(save_dir, video_name)
    if not os.path.exists(video_dir):
        os.makedirs(video_dir)

    split_video_ffmpeg([video_path], scene_list,
                       os.path.join(video_dir,
                                    "${VIDEO_NAME}-${SCENE_NUMBER}.mp4"),
                       video_name)

    return start_video_num, end_video_num, len(scene_list)
Exemplo n.º 10
0
        print('List of scenes obtained:')
        final_scene_list = []
        for i, scene in enumerate(scene_list):
            temp = list(scene)
            # print(temp)
            temp[0] = temp[0] + 1
            temp[1] = temp[1] - 1
            scene = tuple(temp)
            final_scene_list.append(scene)

    finally:
        video_manager.release()

    return final_scene_list

def file_prepare():
    file_list = []
    for root, dirs, files in os.walk(input_dir):
        file_list = [input_dir+"/"+i for i in files]
    return file_list

_file_list = file_prepare()
for key in _file_list:
    scenes = find_scenes(key)
    print(scenes)
    file_path, full_name = os.path.split(key)
    f_name, ext = os.path.splitext(full_name)
    split_video_ffmpeg([key], scenes, "$VIDEO_NAME - Scene $SCENE_NUMBER.mp4", output_dir+"/"+f_name, arg_override='-c:v libx264 -preset slow -crf 20 -c:a aac', hide_progress=False, suppress_output=False)

Exemplo n.º 11
0
def split_video(video_path, video_name, save_dir_path, threshold):
    """
    Oversegment the input video using PySceneDetect

    Patameters
    ----------
    video_path : string
        path to input video
    video_name : string
        name of input video
    save_dir_path : string
        path to saving split elements
    threshold : int
        PySceneDetect threshold
    """

    cv2.setNumThreads(1)

    # type: (str) -> List[Tuple[FrameTimecode, FrameTimecode]]
    video_manager = VideoManager([video_path])
    stats_manager = StatsManager()
    # Construct our SceneManager and pass it our StatsManager.
    scene_manager = SceneManager(stats_manager)

    # Add ContentDetector algorithm (each detector's constructor
    # takes detector options, e.g. threshold).
    scene_manager.add_detector(
        ContentDetector(threshold=threshold, min_scene_len=180))
    base_timecode = video_manager.get_base_timecode()

    # We save our stats file to {VIDEO_PATH}.stats.csv.
    stats_file_path = 'stats/%s.stats.csv' % video_name

    scene_list = []

    try:
        # If stats file exists, load it.
        if os.path.exists(stats_file_path):
            # Read stats from CSV file opened in read mode:
            with open(stats_file_path, 'r') as stats_file:
                stats_manager.load_from_csv(stats_file, base_timecode)

        # Set downscale factor to improve processing speed.
        video_manager.set_downscale_factor()

        # Start video_manager.
        video_manager.start()

        # Perform scene detection on video_manager.
        scene_manager.detect_scenes(frame_source=video_manager)

        # Obtain list of detected scenes.
        scene_list = scene_manager.get_scene_list(base_timecode)
        # Each scene is a tuple of (start, end) FrameTimecodes.

    finally:
        video_manager.release()

    if not os.path.exists(save_dir_path):
        os.makedirs(save_dir_path)

    split_video_ffmpeg(
        [video_path],
        scene_list,
        os.path.join(save_dir_path, "${VIDEO_NAME}-${SCENE_NUMBER}.mp4"),
        video_name[:-4],
        arg_override='-threads 1 -c:v libx264 -preset fast -crf 21 -c:a aac')

    timecode_list = []
    for scene in scene_list:
        start = scene[0].get_timecode()
        end = scene[1].get_timecode()
        timecode_list.append((start, end))

    return timecode_list
Exemplo n.º 12
0
    def process_input(self):
        # type: () -> None
        """ Process Input: Processes input video(s) and generates output as per CLI commands.

        Run after all command line options/sub-commands have been parsed.
        """
        logging.debug('Processing input...')
        if not self.options_processed:
            logging.debug('Skipping processing, CLI options were not parsed successfully.')
            return
        self.check_input_open()
        if not self.scene_manager.get_num_detectors() > 0:
            logging.error(
                'No scene detectors specified (detect-content, detect-threshold, etc...),\n'
                '  or failed to process all command line arguments.')
            return

        # Handle scene detection commands (detect-content, detect-threshold, etc...).
        self.video_manager.start()
        base_timecode = self.video_manager.get_base_timecode()

        start_time = time.time()
        logging.info('Detecting scenes...')

        num_frames = self.scene_manager.detect_scenes(
            frame_source=self.video_manager, frame_skip=self.frame_skip,
            show_progress=not self.quiet_mode)

        duration = time.time() - start_time
        logging.info('Processed %d frames in %.1f seconds (average %.2f FPS).',
                     num_frames, duration, float(num_frames)/duration)

        # Handle -s/--statsfile option.
        if self.stats_file_path is not None:
            if self.stats_manager.is_save_required():
                with open(self.stats_file_path, 'wt') as stats_file:
                    logging.info('Saving frame metrics to stats file: %s',
                                 os.path.basename(self.stats_file_path))
                    self.stats_manager.save_to_csv(
                        stats_file, base_timecode)
            else:
                logging.debug('No frame metrics updated, skipping update of the stats file.')

        # Get list of detected cuts and scenes from the SceneManager to generate the required output
        # files with based on the given commands (list-scenes, split-video, save-images, etc...).
        cut_list = self.scene_manager.get_cut_list(base_timecode)
        scene_list = self.scene_manager.get_scene_list(base_timecode)
        video_paths = self.video_manager.get_video_paths()
        video_name = os.path.basename(video_paths[0])
        if video_name.rfind('.') >= 0:
            video_name = video_name[:video_name.rfind('.')]

        # Ensure we don't divide by zero.
        if scene_list:
            logging.info('Detected %d scenes, average shot length %.1f seconds.',
                         len(scene_list),
                         sum([(end_time - start_time).get_seconds()
                              for start_time, end_time in scene_list]) / float(len(scene_list)))
        else:
            logging.info('No scenes detected.')

        # Handle list-scenes command.
        if self.scene_list_output:
            scene_list_filename = Template(self.scene_list_name_format).safe_substitute(
                VIDEO_NAME=video_name)
            if not scene_list_filename.lower().endswith('.csv'):
                scene_list_filename += '.csv'
            scene_list_path = self.get_output_file_path(
                scene_list_filename, self.scene_list_directory)
            logging.info('Writing scene list to CSV file:\n  %s', scene_list_path)
            with open(scene_list_path, 'wt') as scene_list_file:
                write_scene_list(scene_list_file, scene_list, cut_list)
        # Handle `list-scenes`.
        if self.print_scene_list:
            logging.info("""Scene List:
-----------------------------------------------------------------------
 | Scene # | Start Frame |  Start Time  |  End Frame  |   End Time   |
-----------------------------------------------------------------------
%s
-----------------------------------------------------------------------
""", '\n'.join(
    [' |  %5d  | %11d | %s | %11d | %s |' % (
        i+1,
        start_time.get_frames(), start_time.get_timecode(),
        end_time.get_frames(), end_time.get_timecode())
     for i, (start_time, end_time) in enumerate(scene_list)]))


        if cut_list:
            logging.info('Comma-separated timecode list:\n  %s',
                         ','.join([cut.get_timecode() for cut in cut_list]))

        # Handle save-images command.
        if self.save_images:
            self._generate_images(scene_list=scene_list, video_name=video_name,
                                  image_name_template=self.image_name_format,
                                  output_dir=self.image_directory)

        # Handle export-html command.
        if self.export_html:
            html_filename = Template(self.html_name_format).safe_substitute(
                VIDEO_NAME=video_name)
            if not html_filename.lower().endswith('.html'):
                html_filename += '.html'
            html_path = self.get_output_file_path(
                html_filename, self.image_directory)
            logging.info('Exporting to html file:\n %s:', html_path)
            if not self.html_include_images:
                self.image_filenames = None
            write_scene_list_html(html_path, scene_list, cut_list,
                                  image_filenames=self.image_filenames,
                                  image_width=self.image_width,
                                  image_height=self.image_height)

        # Handle split-video command.
        if self.split_video:
            # Add proper extension to filename template if required.
            dot_pos = self.split_name_format.rfind('.')
            if self.split_mkvmerge and not self.split_name_format.endswith('.mkv'):
                self.split_name_format += '.mkv'
            # Don't add if we find an extension between 2 and 4 characters
            elif not (dot_pos >= 0) or (
                    dot_pos >= 0 and not
                    ((len(self.split_name_format) - (dot_pos+1) <= 4 >= 2))):
                self.split_name_format += '.mp4'

            output_file_prefix = self.get_output_file_path(
                self.split_name_format, output_dir=self.split_directory)
            mkvmerge_available = is_mkvmerge_available()
            ffmpeg_available = is_ffmpeg_available()
            if mkvmerge_available and (self.split_mkvmerge or not ffmpeg_available):
                if not self.split_mkvmerge:
                    logging.warning(
                        'ffmpeg not found, falling back to fast copy mode (split-video -c/--copy).')
                split_video_mkvmerge(video_paths, scene_list, output_file_prefix, video_name,
                                     suppress_output=self.quiet_mode or self.split_quiet)
            elif ffmpeg_available:
                if self.split_mkvmerge:
                    logging.warning('mkvmerge not found, falling back to normal splitting'
                                    ' mode (split-video).')
                split_video_ffmpeg(video_paths, scene_list, output_file_prefix,
                                   video_name, arg_override=self.split_args,
                                   hide_progress=self.quiet_mode,
                                   suppress_output=self.quiet_mode or self.split_quiet)
            else:
                if not (mkvmerge_available or ffmpeg_available):
                    error_strs = ["ffmpeg/mkvmerge is required for split-video [-c/--copy]."]
                else:
                    error_strs = [
                        "{EXTERN_TOOL} is required for split-video{EXTRA_ARGS}.".format(
                            EXTERN_TOOL='mkvmerge' if self.split_mkvmerge else 'ffmpeg',
                            EXTRA_ARGS=' -c/--copy' if self.split_mkvmerge else '')]
                error_strs += ["Install one of the above tools to enable the split-video command."]
                error_str = '\n'.join(error_strs)
                logging.debug(error_str)
                raise click.BadParameter(error_str, param_hint='split-video')
            if scene_list:
                logging.info('Video splitting completed, individual scenes written to disk.')
Exemplo n.º 13
0
def spliter(file_name, frame_rate=25, threshold=55):
    print('detecting scenes...')
    STATS_FILE_PATH = './' + os.path.basename(
        os.path.splitext(file_name)[0]) + '.csv'
    # print(STATS_FILE_PATH)
    # print(file_name)
    scenes = list()

    # print("Running PySceneDetect API test...")

    # print("PySceneDetect version being used: %s" % str(scenedetect.__version__))

    # Create a video_manager point to video file testvideo.mp4. Note that multiple
    # videos can be appended by simply specifying more file paths in the list
    # passed to the VideoManager constructor. Note that appending multiple videos
    # requires that they all have the same frame size, and optionally, framerate.
    video_manager = VideoManager([file_name])
    stats_manager = StatsManager()
    scene_manager = SceneManager(stats_manager)
    # Add ContentDetector algorithm (constructor takes detector options like threshold).
    scene_manager.add_detector(
        ContentDetector(threshold=55.0, min_scene_len=288))
    base_timecode = video_manager.get_base_timecode()
    # print(base_timecode)

    try:
        # If stats file exists, load it.
        if os.path.exists(STATS_FILE_PATH):
            # Read stats from CSV file opened in read mode:
            with open(STATS_FILE_PATH, 'r') as stats_file:
                stats_manager.load_from_csv(stats_file, base_timecode)

        start_time = base_timecode + 20  # 00:00:00.667
        end_time = base_timecode + 20.0  # 00:00:20.000
        # Set video_manager duration to read frames from 00:00:00 to 00:00:20.
        video_manager.set_duration(start_time=start_time)
        # , end_time=end_time

        # Set downscale factor to improve processing speed.
        video_manager.set_downscale_factor()

        # Start video_manager.
        video_manager.start()

        # Perform scene detection on video_manager.
        scene_manager.detect_scenes(frame_source=video_manager,
                                    start_time=start_time)

        # Obtain list of detected scenes.
        scene_list = scene_manager.get_scene_list(base_timecode)

        # Like FrameTimecodes, each scene in the scene_list can be sorted if the
        # list of scenes becomes unsorted.

        # print('List of scenes obtained:')
        # for i, scene in enumerate(scene_list):
        # print('    Scene %2d: Start %s / Frame %d, End %s / Frame %d' % (
        #     i+1,
        #     scene[0].get_timecode(), scene[0].get_frames(),
        #     scene[1].get_timecode(), scene[1].get_frames(),))
        # print('scene[0] is {}, scene[1] is {}, i+1 is {}'.format(scene[0], scene[1], i+1) )
        # scenes.append((scene[0], scene[1]))
        # print('-------------------------------------------------------------------------------------------------')
        # print('ffmpeg -ss {} -i testvideo.mp4 -c:v libx264 -t {} -an test-scene-{}.mp4'.format(scene[0],
        #                                                                                        scene[1], i + 1))

        # We only write to the stats file if a save is required:
        if stats_manager.is_save_required():
            with open(STATS_FILE_PATH, 'w') as stats_file:
                stats_manager.save_to_csv(stats_file, base_timecode)

        # is_ffmpeg_available()
        # print(scene_list)

        scenes = split_video_ffmpeg(
            [file_name], scene_list, '$VIDEO_NAME-Scene-$SCENE_NUMBER.mp4',
            os.path.basename(os.path.splitext(file_name)[0]) + '-reference',
            '-c:v libx264 -preset fast -crf 18 -an')

    finally:
        video_manager.release()

    return scenes