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

Get correct frame amount for video files without nb_frames property & allow codec selection #246

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ demo_movies export-ignore
.gitignore export-ignore
.readthedocs.yaml export-ignore
codecov.yml export-ignore
.github export-ignore
.github export-ignore
demo_movies/*.mkv filter=lfs diff=lfs merge=lfs -text
3 changes: 3 additions & 0 deletions demo_movies/sample1.mkv
Git LFS file not shown
11 changes: 10 additions & 1 deletion minian/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,15 @@ def load_avi_lazy(fname: str) -> darr.array:
video_info = next(s for s in probe["streams"] if s["codec_type"] == "video")
w = int(video_info["width"])
h = int(video_info["height"])
f = int(video_info["nb_frames"])
if "nb_frames" in video_info:
f = int(video_info["nb_frames"])
else:
r_fps = video_info["r_frame_rate"]
num, denom = r_fps.split("/")
fps = float(num) / float(denom)
f = float(probe["format"]["duration"]) * fps
f = np.round(f).astype(int)

return da.array.from_delayed(
da.delayed(load_avi_ffmpeg)(fname, h, w, f), dtype=np.uint8, shape=(f, h, w)
)
Expand Down Expand Up @@ -257,6 +265,7 @@ def load_avi_ffmpeg(fname: str, h: int, w: int, f: int) -> np.ndarray:
out_bytes, err = (
ffmpeg.input(fname)
.video.output("pipe:", format="rawvideo", pix_fmt="gray")
.global_args("-hide_banner", "-nostats")
.run(capture_stdout=True)
)
return np.frombuffer(out_bytes, np.uint8).reshape(f, h, w)
Expand Down
22 changes: 20 additions & 2 deletions minian/visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -1217,7 +1217,9 @@ def write_video(
vname: Optional[str] = None,
vpath: Optional[str] = ".",
norm=True,
vcodec="libx264",
options={"crf": "18", "preset": "ultrafast"},
verbose=True,
) -> str:
"""
Write a video from a movie array using `python-ffmpeg`.
Expand All @@ -1235,9 +1237,13 @@ def write_video(
norm : bool, optional
Whether to normalize the values of the input array such that they span
the full pixel depth range (0, 255). By default `True`.
vcodec : str, optional
Name of the ffmpeg video encoder to use. By default `"libx264"`.
options : dict, optional
Optional output arguments passed to `ffmpeg`. By default `{"crf": "18",
"preset": "ultrafast"}`.
verbose : bool, optional
Display verbose ffmpeg output. By default `True`.

Returns
-------
Expand Down Expand Up @@ -1265,11 +1271,15 @@ def write_video(
arr *= 255
arr = arr.clip(0, 255).astype(np.uint8)
w, h = arr.sizes["width"], arr.sizes["height"]
verbosity_args = ["-hide_banner", "-nostats"]
if verbose:
verbosity_args = []
process = (
ffmpeg.input("pipe:", format="rawvideo", pix_fmt="gray", s="{}x{}".format(w, h))
.filter("pad", int(np.ceil(w / 2) * 2), int(np.ceil(h / 2) * 2))
.output(fname, pix_fmt="yuv420p", vcodec="libx264", r=30, **options)
.output(fname, pix_fmt="yuv420p", vcodec=vcodec, r=30, **options)
.overwrite_output()
.global_args(*verbosity_args)
.run_async(pipe_stdin=True)
)
for blk in arr.data.blocks:
Expand Down Expand Up @@ -1306,7 +1316,9 @@ def generate_videos(
gain=1.5,
vpath=".",
vname="minian.mp4",
vcodec="libx264",
options={"crf": "18", "preset": "ultrafast"},
verbose=True,
) -> str:
"""
Generate a video visualizaing the result of minian pipeline.
Expand Down Expand Up @@ -1351,9 +1363,13 @@ def generate_videos(
Desired folder containing the resulting video. By default `"."`.
vname : str, optional
Desired name of the video. By default `"minian.mp4"`.
vcodec : str, optional
Name of the ffmpeg video encoder to use. By default `"libx264"`.
options : dict, optional
Output options for `ffmpeg`, passed directly to :func:`write_video`. By
default `{"crf": "18", "preset": "ultrafast"}`.
verbose : bool, optional
Display verbose ffmpeg output. By default `True`.

Returns
-------
Expand Down Expand Up @@ -1388,7 +1404,9 @@ def generate_videos(
"height",
coords="minimal",
)
return write_video(vid, vname, vpath, norm=False, options=options)
return write_video(
vid, vname, vpath, norm=False, vcodec=vcodec, options=options, verbose=verbose
)


def datashade_ndcurve(
Expand Down