-
-
Notifications
You must be signed in to change notification settings - Fork 253
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
Small number of frames causes no output. #149
Comments
@Thomasedv Keep
Means, you have kept low framerate while extracting those frames. Btw, how you're extracting these frame from video? Can you share the code. SolutionSometimes you may want the input frame rate and output frame rate to differ. For example, you may want to input the frames at a certain rate, and then duplicate or drop frames so the output has a different/higher framerate, as you desired. Try following code instead of yours: from vidgear.gears import WriteGear
from PIL import Image
import os
import numpy as np
import vidgear
print(vidgear.version.__version__)
output_params = {"-input_framerate":25 , #lower than actual framerate to compensate(go even lower if this doesn't works)
'-r': 29.97*2 # Double the framerate of the video, double frames in the frames folder.}
writer = WriteGear(output_filename='test_out.mkv', logging=True, **output_params)
for image in sorted(os.listdir('frames')):
img = Image.open(os.path.join('frames', image))
writer.write(np.asarray(img))
writer.close()
@Thomasedv Are those frames sorted or not? Since, as per the documentation:
To sort the result, use sorted(os.listdir(path)) instead.
Can you zip compress everything(including audio) and upload here(only if possible) for testing.
Thanks for catching that up, I'll fix it. |
Images and video is part of original xbox startup(minor flash warning in case of epilepsy), and the frames are the same video but interpolatated which is why the input has to be double the framerate of the video. This works well for anything else where frames are written. Frames extracted are processed by my original python script, but in this case I just wrote them as png directly instead of using WriteGear. No audio in the original video, I didn't add that when i made the short video. Shouldn't matter for the case at hand, as the lack of audio shouldn't prevent anything from being made. It's my mistake however, but if you insist I can make a new example after work. os.listdir() is sorted by filename on windows, but i added the sorted for good measure, same with the -r tag, i noticed ffmpeg could drop frames without it with my own settings. (because it assumed it was working realtime) But i just went barebones for the sake of the simple code. And again, that i consistently have no output with .terminate() there, and correct video without it, seems pretty likely that the subprocess is killing it before it finished. On Windows it calls the win32 api which has the following documentation:
It's a bit vague for me, but it sounds like it may prevent any IO from happening, not to mention stop ffmpeg from processing the last frames given to it, with any slow encoder it would take longer than the call to close after the last write call. |
@Thomasedv If i recall, I added this |
It's what I assumed. I honestly don't know exactly if that is possible, the best suggestion I have is to add a keyword argument to the close method that let's users turn of the termination. Eg. Have a I would think ffmpeg has some potential options, I'm not at liberty to test for a while, but the |
This comment has been minimized.
This comment has been minimized.
@Thomasedv Yep, that's the only way to address this problem. I'm in favor of somewhat much easier approach, i.e. add options = {'-disable_force_termination': true} # manually disables the `terminate()` callback. |
That seems proper. I'd hold on implementing until one of us has tested the ffmpeg flag i mentioned , it might just do the job for us, and can be either manually or automatically added to the outout_params as well. And optionally be disabled just like termination. And I feel that if you can avoid termination altogether you'll be handling stopping much better overall. I can do a test of that once I'm off work. On the topic of time.sleep, I think it would be too arbitrary, in edge cases where encoding takes a long time, eg. AV1 encoding with vmaf tune, I think one frame can take upwards to 30 sec for example going by a post i saw earlier. Which may leave the user in the same situation. |
@Thomasedv If there's another way to tackle that bug more adequately, I'll merge it without hesitation. Thanks. |
@abhiTronix I looked into it briefly, but ended up with files with no video when i tried using the '-shortest' argument. So far, it seems like the '-disable_force_termination' options is the way to go. |
@Thomasedv Give me few days, as I'm stacked up with work right now. I'll notify you here when I'll be pushing related commits. |
- Added support to disable force-termination (Fixes #149) - Replaced `call()` with new `run()` for better error handling. - Fixed several CLI bugs. - Fixed Issue Template outdated link.
@Thomasedv Thanks for your patience. Kindly try #145 PR by installing # clone the repository and get inside
git clone https://github.com/abhiTronix/vidgear.git && cd vidgear
# checkout the latest testing branch
git checkout development
# install normally
pip install .
# OR install with asyncio support
pip install .[asyncio] and check if it works as you expected or not? |
Successfully resolved and merged in commit d76c8be. |
@Thomasedv Closed and marked solved for now. Kindly share your results when you're ready. Good luck! |
Used testing branch as development is removed at time of writing. Pardon the delayed response. The option probably works, but ffmpeg crashes due to the option not being deleted from the output parameters before being passed to it. Also, as per the docs in the referenced commit, the default usage is letting the user provide a boolean, but this is not checked in the actual code, only the existence of the termination key. This may lead a user to incorrectly assume that passing the flag with the a False value will cause the default behavior, when it does not. To solve both issues, i propose to change the following lines vidgear/vidgear/gears/writegear.py Lines 183 to 186 in d76c8be
to the following: if "-disable_force_termination" in self.__output_parameters:
self.__force_termination = not self.__output_parameters.get("-disable_force_termination")
del self.__output_parameters["-disable_force_termination"] Edit: Removed some comment, reading old Stack Overflow for too old python versions is not always good. |
Thanks @Thomasedv I'm on it ASAP. On a side note, I thinks you should contribute to this project, if possible, as you understand vidgear code very well. I'm working on streaming feature next, if you can help, i'll much appreciate it. |
I'd could have made pull requests for these things, it just that i have no experience when it comes to creating pull requests and such. While i can say i have a pretty decent understanding of writegear.py, i can't say as much for the rest of VidGear. Streaming isn't my strong side either, but I'm happy to have a look at it, just not sure how much i can actually do. |
@Thomasedv the bug is fixed in testing branch, you can check it again. Thanks. |
boolean needs to be changed to bool. Crashes otherwise since it's not defined. There's also an edge case if the user provides the termination flag, but not "-i" where that key is not removed. It's not pretty, but the following code is a suggested fix: # activate force termination
if "-disable_force_termination" in self.__output_parameters:
if "-i" in self.__output_parameters:
self.__force_termination = (
self.__output_parameters["-disable_force_termination"]
if isinstance(
self.__output_parameters["-disable_force_termination"],
bool,
)
else False
)
else:
self.__force_termination = False
del self.__output_parameters["-disable_force_termination"] # clean
else:
self.__force_termination = False Edit: Flipped a boolean. |
Lmao, I'm too much into java these days. 😆
Yes, this won't work. I need to think something else, as we need |
@Thomasedv I've corrected the bugs, you can give it an another try. |
Tested it quickly, and seems to be working. Thanks again for the good work! |
Description
I an trying to make a video from a low number of frames. However, the ffmpeg process is terminated before the writing is finished. I also add audio from a clip that has the same duration as the video made. It's also possible this causes the last few frames of longer clips to go missing as well, but isn't that noticable unless you pay attention at the end, expect for situation where chapters won't show due to incomplete file closes. (Which happens with ffmpeg, copying such files with ffmpeg again will reintroduce the chapters in a video. Pardon the sidestep, but i have had that problem with WriteGear as well, so i strongly suspect it the same cause.)
(Note: In the example below, the clip doesn't have audio but the result is still the same.)
Acknowledgment
Environment
Expected Behavior
Expected video
Actual Behavior
0 byte file is made.
Possible Fix
The ffmpeg process is terminated when calling
close()
with the-i
flag is supplied as a parameter, which i assume kills ffmpeg before it has finished processing the frames. There are many situations where slower encoders are picked where there closing might happen before a frame write happens.Relevant line of code:
vidgear/vidgear/gears/writegear.py
Lines 534 to 535 in b9d1109
Steps to reproduce
Debug setup
In folder:
vid.webm # Video where audio is copied from (14 Frames)
frames # Folder with frames for vidgear (both video and frames can be uploaded)
Code:
Default ffmpeg is used, and let Writegear handle output format and everything
Logging:
Logging with the mentioned lines commented out: (which has working result)
Take note how there is stuff printed after calling close in this last log, but not in the first one. While i do know printing doesn't follow proper ordering, i do still believe this to be accurate here. After close is called, the ffmpeg process is terminated and won't continue so nothing is printed.
When run, there is created a 0 byte file, the typical ones created by ffmpeg before frames have been written to it. Commenting out the code mentioned above, makes a proper video file.
The text was updated successfully, but these errors were encountered: