Search code examples
pythonffmpeganacondasubprocessffmpeg-python

FileNotFoundError: [WinError 2] The system cannot find the file specified - FFMPEG


I am running a script using conda environment on Windows and getting this error (stack trace below), which is apparently caused by python executable not being able to find the ffmpeg.exe. There are numerous questions about this, but none of the solutions unfortunately worked for me, so I hope someone has fresh ideas.

What I tried:

  • conda install -c conda-forge ffmpeg (after this I can run ffmpeg in command line, but still getting the error)
  • pip install ffmpeg-python
  • Added the folder where ffmpeg.exe is located in conda env to the Windows Path as well as to sys.path in python.
  • copied the same ffmpeg.exe a) to the location of python.exe in conda env, b) to the location of the script I am running, c) to the location of subprocess.py.
  • Downloaded ffmpeg windows binary and repeated the last two steps with that file.

Is there anything else that I can try to make it work?

---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
Cell In[10], line 22
     19 truncate_second = 8.2         # Video end = start_second + truncate_second
     21 # Extract Video CAVP Features & New Video Path:
---> 22 cavp_feats, new_video_path = extract_cavp(video_path, start_second, truncate_second, tmp_path=tmp_path)

File D:\Software\Anaconda\envs\diff_foley\Lib\site-packages\torch\nn\modules\module.py:1518, in Module._wrapped_call_impl(self, *args, **kwargs)
   1516     return self._compiled_call_impl(*args, **kwargs)  # type: ignore[misc]
   1517 else:
-> 1518     return self._call_impl(*args, **kwargs)

File D:\Software\Anaconda\envs\diff_foley\Lib\site-packages\torch\nn\modules\module.py:1527, in Module._call_impl(self, *args, **kwargs)
   1522 # If we don't have any hooks, we want to skip the rest of the logic in
   1523 # this function, and just call forward.
   1524 if not (self._backward_hooks or self._backward_pre_hooks or self._forward_hooks or self._forward_pre_hooks
   1525         or _global_backward_pre_hooks or _global_backward_hooks
   1526         or _global_forward_hooks or _global_forward_pre_hooks):
-> 1527     return forward_call(*args, **kwargs)
   1529 try:
   1530     result = None

File D:\Software\Anaconda\envs\diff_foley\Lib\site-packages\torch\utils\_contextlib.py:115, in context_decorator.<locals>.decorate_context(*args, **kwargs)
    112 @functools.wraps(func)
    113 def decorate_context(*args, **kwargs):
    114     with ctx_factory():
--> 115         return func(*args, **kwargs)

File D:\Work\DIff-Foley\Diff-Foley\inference\demo_util.py:131, in Extract_CAVP_Features.forward(self, video_path, start_second, truncate_second, tmp_path)
    129 print("truncate second: ", truncate_second)
    130 # Load the video, change fps:
--> 131 video_path_low_fps = reencode_video_with_diff_fps(video_path, self.tmp_path, self.fps, start_second, truncate_second)
    132 video_path_high_fps = reencode_video_with_diff_fps(video_path, self.tmp_path, 21.5, start_second, truncate_second)
    134 # read the video:

File D:\Work\DIff-Foley\Diff-Foley\inference\demo_util.py:42, in reencode_video_with_diff_fps(video_path, tmp_path, extraction_fps, start_second, truncate_second)
     31 def reencode_video_with_diff_fps(video_path: str, tmp_path: str, extraction_fps: int, start_second, truncate_second) -> str:
     32     '''Reencodes the video given the path and saves it to the tmp_path folder.
     33 
     34     Args:
   (...)
     40         str: The path where the tmp file is stored. To be used to load the video from
     41     '''
---> 42     assert which_ffmpeg() != '', 'Is ffmpeg installed? Check if the conda environment is activated.'
     43     # assert video_path.endswith('.mp4'), 'The file does not end with .mp4. Comment this if expected'
     44     # create tmp dir if doesn't exist
     45     os.makedirs(tmp_path, exist_ok=True)

File D:\Work\DIff-Foley\Diff-Foley\inference\demo_util.py:26, in which_ffmpeg()
     20 def which_ffmpeg() -> str:
     21     '''Determines the path to ffmpeg library
     22 
     23     Returns:
     24         str -- path to the library
     25     '''
---> 26     result = subprocess.run(['which', 'ffmpeg'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
     27     ffmpeg_path = result.stdout.decode('utf-8').replace('\n', '')
     28     return ffmpeg_path

File D:\Software\Anaconda\envs\diff_foley\Lib\subprocess.py:548, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    545     kwargs['stdout'] = PIPE
    546     kwargs['stderr'] = PIPE
--> 548 with Popen(*popenargs, **kwargs) as process:
    549     try:
    550         stdout, stderr = process.communicate(input, timeout=timeout)

File D:\Software\Anaconda\envs\diff_foley\Lib\subprocess.py:1026, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize, process_group)
   1022         if self.text_mode:
   1023             self.stderr = io.TextIOWrapper(self.stderr,
   1024                     encoding=encoding, errors=errors)
-> 1026     self._execute_child(args, executable, preexec_fn, close_fds,
   1027                         pass_fds, cwd, env,
   1028                         startupinfo, creationflags, shell,
   1029                         p2cread, p2cwrite,
   1030                         c2pread, c2pwrite,
   1031                         errread, errwrite,
   1032                         restore_signals,
   1033                         gid, gids, uid, umask,
   1034                         start_new_session, process_group)
   1035 except:
   1036     # Cleanup if the child failed starting.
   1037     for f in filter(None, (self.stdin, self.stdout, self.stderr)):

File D:\Software\Anaconda\envs\diff_foley\Lib\subprocess.py:1538, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, unused_restore_signals, unused_gid, unused_gids, unused_uid, unused_umask, unused_start_new_session, unused_process_group)
   1536 # Start the process
   1537 try:
-> 1538     hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
   1539                              # no special security
   1540                              None, None,
   1541                              int(not close_fds),
   1542                              creationflags,
   1543                              env,
   1544                              cwd,
   1545                              startupinfo)
   1546 finally:
   1547     # Child is launched. Close the parent's copy of those pipe
   1548     # handles that only the child should have open.  You need
   (...)
   1551     # pipe will not close when the child process exits and the
   1552     # ReadFile will hang.
   1553     self._close_pipe_fds(p2cread, p2cwrite,
   1554                          c2pread, c2pwrite,
   1555                          errread, errwrite)

FileNotFoundError: [WinError 2] The system cannot find the file specified

Solution

  • You need to put the ffmpeg.exe in the path either via environment variable or manipulating sys.path during Python runtime.

    There are a couple convenience alternatives that I'm aware of.

    1. ffmpeg-downloader (I'm the dev.)

    This package gives you a pip-like command to download the latest (and other versions of) ffmpeg. This one installs ffmpeg to user's AppData directory for use across multiple Python venvs (or other general use).

    A quick use:

    pip install ffmpeg-downloader
    ffdl install --add-path
    

    See the repo readme for other usages.

    1. static-ffmpeg

    This one on the other hand downloads the ffmpeg to the current venv.

    If you don't use venv's, either should work for you. If you use ffmpeg in multiple projects with venv, I suggest using the former.