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

PyAV plugin always produces 480x640 when filters are specified #1009

Open
djhoese opened this issue Jun 19, 2023 · 2 comments
Open

PyAV plugin always produces 480x640 when filters are specified #1009

djhoese opened this issue Jun 19, 2023 · 2 comments

Comments

@djhoese
Copy link

djhoese commented Jun 19, 2023

I have some input data that depends on how the user sizes my GUI window so I can't guarantee things required by ffmpeg like frame sizes divisible by 2. To get around that I add a filter used by ffmpeg to scale the frame to the nearest 16 pixels. This is similar to what imageio-ffmpeg does to make frames consistent with the "macro block size".

When a filter is provided it seems that imageio/pyav always produces a video of 480x640 pixels instead of a size based on the input frames. From what I can tell the issue in the pyav plugin is that it provides the filters the video stream before it is full initialized during the frame writing. Is there a way around this?

import imageio.v3 as imageio
import numpy as np

imageio.imwrite("test.mp4", [np.zeros((512, 512, 3), dtype=np.uint8) for i in range(10)], plugin="pyav", codec="libx264")

imageio.imread("test.mp4", plugin="pyav").shape
# (10, 512, 512, 3)


imageio.imwrite("test.mp4", [np.zeros((512, 512, 3), dtype=np.uint8) for i in range(10)], plugin="pyav", codec="libx264", filter_sequence=[("scale", "iw+gt(mod(iw,16), 0)*(16-mod(iw,16)):ih+gt(mod(ih,16), 0)*(16-mod(ih,16))")])

imageio.imread("test.mp4", plugin="pyav").shape
# (10, 480, 640, 3)
@djhoese
Copy link
Author

djhoese commented Jun 19, 2023

I was able to get this to work by swapping the if blocks here:

if self._video_filter is not None:
av_frame = self._video_filter.send(av_frame)
if av_frame is None:
return
if stream.frames == 0:
stream.width = av_frame.width
stream.height = av_frame.height

But only in cases where my frame was already divisible by 2 (and possibly only when the filter didn't change the frame size). I think it is because the frame influences the stream size (width/height) but the stream influences how the filter behaves (chicken/egg problem).

@Ai-Himmel
Copy link
Contributor

Seems to be #1003

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

No branches or pull requests

2 participants