I am trying to extract particular sub clips from videos and I see that when the duration of the sub clip is shorter (around 2- 3 seconds), only black frames are seen in the subclip. I guess this might be because ffmpeg is unable to locate the key frames. How do I deal with this?
Hey - That's not enough informations and I've never seen this before, can you provide some code to reproduce the issue ? (and possibly a videofile for which the issue exists too)
Hi, I recreated the issue using this gist https://gist.github.com/ksharsha/f28ca2f019070389c38741fb90a077d1 . I am attaching the video file as well. You can see that the audio is still preserved however, the video is completely blank. This is the video that I am trying to extract the subclip from (tstart = 12.334277199999999, tend = 15.97166675). This is the video https://www.youtube.com/watch?v=a-6lVnhqU4w
Videos.zip
It seems like this might help..
https://trac.ffmpeg.org/wiki/Seeking
when I try what is recommended by this link, I do get video, but the video seems to be a bit messed up (like a bad key frame). I'm not very good with ffmpeg, so maybe someone else sees a solution?
@earney true, the problem is with this cmd = [get_setting("FFMPEG_BINARY"),"-y",
"-i", filename,
"-ss", "%0.2f"%t1,
"-t", "%0.2f"%(t2-t1),
"-vcodec", "copy", "-acodec", "copy", targetname]
I am not good with ffmpeg either but looks like the above cmd has to be changed.
Is this issue resolved? Is there any other way instead of using ffmpeg_extract_subclip to clip videos?
Looks like PR #579 could fix this.
Hi !
There is https://github.com/Zulko/moviepy/pull/848 which is quite clear and well-documented. It seems if fell unoticed, but it does fix this issue, in a better way than #579. (It might not be THE universal fix but it seems very correct)
It would be cool if it could get merged soon :) this issue is getting old, and remains kinda annoying :smile:
Regards
Updating to say I believe this may still be a problem. Using ffmpeg_extract_subclip for 2-3 second clips and continue to run into this issue. As far as I can tell, the only way to get the frame back is removing the copy/encode options, but this reduces the picture in quality.
@ebenz99 Should we reopen this issue?
Up to you. I ended up just using the workaround I mentioned (removing some options and taking a quality hit), but it might be nice to not have to do that.
This is an issue for me, I'm using moviepy to automate the refining of a machine learning dataset and the samples need all the quality it can get.
Even with the quality hit, I'm not sure how to remove the copy/encode options, as I'm not passing any copy/encode options to ffmpeg_extract_subclip()
Any update on this issue @jeff-hykin ?? I am in the very same position as you were back at the time that you commented on this
Which options did you remove @ebenz99 ??
Because most of my time segments were tiny (less than 1 second), and I couldn't sacrifice on quality, I currently use opencv to load all of the frames, skip to the needed subsection, pull out all the frames, and then create a new video with those frames.
My older method was a direct call to ffmpeg. I gave up on the movie.py library
from subprocess import call,run
from pathlib import Path
import os
def cut_video(source, start, end, output_path, hide_errors=False, errors_to_ignore=None):
"""
Example:
exit_code, stdout, stderr = cut_video(source="./myvid.mp4", start=30, end=60, output_path="./myvid_30to60.mp4")
Note:
- this will not modify the existing video
- this was tested with ffmpeg 4.3.1
Args:
source: filepath to the video
start: seconds (float or int)
end: seconds (float or int)
output_path: filepath to new clip
hide_errors: print or dont print stderr
errors_to_ignore: list of strings, if string is in the stderr the stderr wont be printed
Returns:
(exit_code, stdout, stderr)
Raises:
Exception: "End time is before start time for "+source
Exception: "When calling cut_video() it seems ffmpeg is not installed (or not on the path). This was called with "+source
Exception: "When calling cut_video() it seems the video didn't exist as a file: "+source
"""
errors_to_ignore = [] if errors_to_ignore is None else errors_to_ignore
duration = end - start
# check start/end
if duration <= 0:
raise Exception("End time is before start time for "+source)
# make sure ffmpeg exists (only check once per python process)
if globals().get("__ffpeg_exists", False):
command_output = run(["ffmpeg", "-version",], capture_output=True)
stdout = str(command_output.stdout.decode('UTF-8'))
if "ffmpeg version" in stdout:
globals()["__ffpeg_exists"] = True
else:
raise Exception("When calling cut_video() it seems ffmpeg is not installed (or not on the path). This was called with "+source)
# make sure the video exists
if not os.path.isfile(source):
raise Exception("When calling cut_video() it seems the video didn't exist as a file: "+source)
# touch the original video so that the file system knows it has been used recently
Path(source).touch()
#
# actually run the command
#
command_output = run(["ffmpeg", "-i", str(source), "-ss", str(start), "-t", str(duration), "-async", "1", str(output_path), "-hide_banner", "-loglevel", "panic"], capture_output=True)
# process the output
exit_code = command_output.exit_code
stdout = str(command_output.stdout.decode('UTF-8'))
stderr = str(command_output.stderr.decode('UTF-8'))
if not hide_errors and len(stderr) != 0:
common_errors = [ common_error for common_error in errors_to_ignore if common_error in stderr ]
if len(common_errors) == 0:
print('ffmpeg inside cut_video(source='+str(source)+') produced some errors:')
print(stderr)
return exit_code, stdout, stderr
Reopening because several people commented since close / problem persists.