Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mkvmerge could not be found on system error message when set_duration is large, works fine when set_duration is small #164

Closed
alexboydray opened this issue May 13, 2020 · 2 comments
Labels
Milestone

Comments

@alexboydray
Copy link

Bug/Issue Description:
Please note I have found a workaround for this problem, but thought I would mention it just in case it was something to add to documentation for others.
When attempting to split relatively long movie (2h 04m 27s) using python API, execution of python program fails when attempting to split_video_mkvmerge method, citing error ERROR:root:mkvmerge could not be found on the system. Please install mkvmerge to enable video output support. Plus additional error lines that can be seen below.

When the duration is decreased on the video_manager (tested a 20 second duration) the split_video_mkvmerge method works fine. Furthermore, the output of the is_mkvmerge_available() shows as True.

Here are the contents of the two python files:

main.py

import VideoSplitter

if __name__ == "__main__":
    VideoSplitter.videoSplitter("[1988] Akira (24 FPS).mkv")

VideoSplitter.py

from __future__ import print_function
import os
import subprocess
import scenedetect
from math import ceil
from scenedetect.video_manager import VideoManager
from scenedetect.frame_timecode import FrameTimecode
from scenedetect.detectors import ContentDetector
from scenedetect.scene_detector import SceneDetector
from scenedetect.stats_manager import StatsManager
from scenedetect.scene_manager import SceneManager
from scenedetect import video_splitter


def videoSplitter(media_name):

    video_manager = VideoManager([media_name], framerate=24.0)
    scene_manager = SceneManager()

    scene_manager.add_detector(ContentDetector(threshold=27.0))
    base_timecode = video_manager.get_base_timecode()

    try:
        media_length = float(ceil(get_length(media_name)))

        start_time = base_timecode
        end_time = base_timecode + media_length  # full length of movie in seconds

        # Set video_manager duration to read frames from 00:00:00 until end of movie
        video_manager.set_duration(start_time=start_time, end_time=end_time)

        # Set downscale factor to improve processing speed (no args means default).
        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)

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

        print(
            "Is MKVMerge Available: {0}".format(
                scenedetect.video_splitter.is_mkvmerge_available()
            )
        )
        print("Number of scenes detected: {0}".format(len(scene_list)))

        scenedetect.video_splitter.split_video_mkvmerge(
            [media_name],
            scene_list,
            "Scenes\\Scene.mkv",
            media_name.split(".")[0],
            suppress_output=False,
        )

    finally:
        video_manager.release()


def get_length(filename):
    result = subprocess.run(
        [
            "ffprobe",
            "-v",
            "error",
            "-show_entries",
            "format=duration",
            "-of",
            "default=noprint_wrappers=1:nokey=1",
            filename,
        ],
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
    )
    return float(result.stdout)

Error Received after running main.py

**100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 179020/179020 [25:33<00:00, 116.72frames/s] 
Is MKVMerge Available: True
Number of scenes detected: 4321
ERROR:root:mkvmerge could not be found on the system. Please install mkvmerge to enable video output support.
Traceback (most recent call last):
  File "main.py", line 5, in <module>
    VideoSplitter.videoSplitter("[1988] Akira (24 FPS).mkv")
  File "C:\Users\Alex\Projects\Non-School Related Projects\Modern-Love\Modern-Love-Video-Splitter\VideoSplitter.py", line 60, in videoSplitter
    scenedetect.video_splitter.split_video_mkvmerge(
  File "C:\Python38-64\lib\site-packages\scenedetect\video_splitter.py", line 163, in split_video_mkvmerge
    ret_val = subprocess.call(call_list)
  File "C:\Python38-64\lib\subprocess.py", line 340, in call
    with Popen(*popenargs, **kwargs) as p:
  File "C:\Python38-64\lib\subprocess.py", line 854, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "C:\Python38-64\lib\subprocess.py", line 1307, in _execute_child
    hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
FileNotFoundError: [WinError 206] The filename or extension is too long**

Expected Behavior:
Expected all individual scenes to be exported to Scenes\ directory. Program works correctly when the duration is lowered but not when trying to split longer length media.

Computing Environment:

  • OS: Windows 10
  • Python Version: 3.8.2 64bit
  • OpenCV Version: 4.2.0.34

Workaround
After digging into the WinError 206, I discovered that in Windows a process command line is limited to 32,766 characters. This may be what is causing the errors during the mkv splitting, as the amount of scenes in the list is very large. As a workaround I cut the scene_list into 4 portions and then ran each through the split_video_mkvmerge method.

@Breakthrough Breakthrough added this to the v0.6 milestone Jun 23, 2020
@Breakthrough Breakthrough modified the milestones: v0.6, v0.5.4 Aug 8, 2020
@Breakthrough
Copy link
Owner

Breakthrough commented Aug 24, 2020

When you cut it into 4 portions, I think mkvmerge will produce "extras" at the cutoffs, correct? If so, I'll need to figure out how to manage & rename these temporary files - but this is technically possible.

Not sure if it's worth the effort to address though if it's so infrequent and the workaround is obvious (e.g. detect it and tell the user to to just do it manually as you did and run mkvmerge X times, and I would need to add a line in the new FAQ page I'm writing)... I'll give it some thought.

Thank you so much for the thorough report and investigation!

@Breakthrough
Copy link
Owner

Breakthrough commented Aug 27, 2020

Hey @alexboydray;

I've updated the code now to properly detect & provide an error message when this occurs. I'll also add an entry in the FAQ explaining why this occurs and how users can overcome it.

I'd rather not have to actually deal with creating/deleting temporary files as that might incur some risks with respect to code maintenance, so I think so long as the correct message is delivered, that should address the real issue here (and informs people that they can just invoke mkvmerge or ffmpeg themselves with a smaller sub-set of scenes to be cut).

Basically, when this happens now, you will see:

Cannot split video due to too many scenes (resulting command
is too large to process). To work around this issue, you can
split the video manually by exporting a list of cuts with the
list-scenes command.
See www.github.com/Breakthrough/PySceneDetect/issues/164
for details. Sorry about that!

If you're okay with that as a "fix" for this issue, then I'll resolve this after hearing back from you and push it as part of the v0.5.4 release. Thanks again for the report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants