Repository navigation
[cli] Add --stdin to read the input video from a pipe - #598
EnesSoydan wants to merge 3 commits into
Conversation
|
Also FYI I'm trying to get v0.7.3. out right now so I'd like to hold this until after the release just to avoid bringing in any last minute changes. Feel free to continue working on this in the meantime though, I'll make sure we get this landed in the version that we ship just after v0.7.3. Can you also post a quick comment in each of the linked bugs in the PR description so I can assign those issues to you (so folks know it's taken)? Just something like "I'd like to take this on, staged #598 for this" is sufficient. Thanks. |
5296354 to
4605bc2
Compare
Breakthrough
left a comment
There was a problem hiding this comment.
v0.7.3 just shipped, so you can rebase this on main now so we can also run the tests after. Thanks. PTAL the review comments as well.
Breakthrough
left a comment
There was a problem hiding this comment.
(sorry forgot to post the comments on prev. reply)
| " as an MP4 with its index at the end of the file. Try remuxing to MKV or MPEG-TS:\n" | ||
| " ffmpeg -i input.mp4 -c copy -f matroska -\n" | ||
| ) | ||
| raise SystemExit(1) |
There was a problem hiding this comment.
Could _detect() return None here like the OpenCV branch above, and have run_scenedetect() report the failure so main() exits with 1? Then the except SystemExit in __main__.py isn't needed.
| "--stdin", | ||
| is_flag=True, | ||
| default=False, | ||
| help="Read the input video from standard input instead of -i/--input. Requires the pyav backend and a container that can be read from a pipe (e.g. MKV or MPEG-TS). Commands that need to seek in the video are not supported.", |
There was a problem hiding this comment.
Re: the container that can be read part, can we make it more clear how this can be created? e.g. can we reword this to say the MP4 needs its index at the start of the file (ffmpeg -movflags +faststart)? Otherwise, remux to MKV or MPEG-TS? Same text in docs/cli.rst.
| def check_not_stdin(ctx: CliContext, command: str) -> None: | ||
| """Rejects `command` if the input is read from stdin, which cannot seek and has no path.""" | ||
| if ctx.use_stdin: | ||
| raise click.BadParameter(f"{command} is incompatible with --stdin.", param_hint=command) |
There was a problem hiding this comment.
This should be click.UsageError(f"{command} is incompatible with --stdin."), the current message repeats the command name in the logged output via the param_hint.
| # Make sure a save-images command is in the pipeline for us to use the results from if we need | ||
| # to include images. | ||
| include_images = not ctx.config.get_value("save-html", "no-images", no_images) | ||
| no_images = ctx.config.get_value("save-html", "no-images", no_images) or ctx.use_stdin |
There was a problem hiding this comment.
Could you log a message when --stdin forces no_images?
| "--stdin requires the pyav backend. Install it with `pip install av`.", | ||
| param_hint="--stdin", | ||
| ) | ||
| if sys.stdin.isatty(): |
There was a problem hiding this comment.
Should this be sys.stdin is None or sys.stdin.isatty()? sys.stdin is None under pythonw.exe on my Windows computer.
| assert "Processed" not in output | ||
|
|
||
|
|
||
| def test_cli_stdin_unreadable_container(): |
There was a problem hiding this comment.
Please add a comment that makes it clear this relies on testvideo.mp4 having its moov atom at the end.
- Return None from _detect() when no frames are read from stdin, and exit with 1 from main() when run_scenedetect() reports a failure - Explain in the --stdin help that an MP4 needs its index at the start of the file (-movflags +faststart), otherwise remux to MKV or MPEG-TS - Raise UsageError for commands that are incompatible with --stdin - Warn when save-html leaves out images because of --stdin - Handle sys.stdin being None (e.g. under pythonw.exe) - Add a CONCORDANCE row for --stdin and regenerate docs/cli.rst - Fix pyright errors in _open_video_stream
|
Thanks for the review! Pushed 97e01e6:
|
Closes #434
Closes #189
Adds a
--stdinflag, so a video can be piped in:This went through the task list in #189:
VideoStreamAv, since PyAV already takes a file-like object.--stdinwith another backend is an error, and so is combining it with-i.split-video,save-images,load-scenes, andtime -s.save-htmlleaves out images.save-fcpandsave-otioare rejected as well, because they write a reference to a source file that doesn't exist here.$VIDEO_NAME: it is set tostdin, so output files get names likestdin-Scenes.csv.I left
split-videofrom a stream out of this PR.Two things I ran into while testing:
sys.stdin.buffer.seekable()returnsTruefor a pipe, and PyAV then fails withOSError: [Errno 22]when it tries to seek._PipeReaderis a small wrapper that reports the stream as non-seekable.__main__.pyletsSystemExitthrough so this isn't logged as an unhandled exception. The existing OpenCV "no frames" path still exits with 0; I didn't change that here.The new tests in
tests/test_cli.pywrite to the CLI through a real pipe. They include a check that the scenes match the same video opened with-i.I edited
docs/cli.rstby hand instead of committing the output ofgenerate_cli_docs.py, because the generator also changed some unrelated lines.Tested on Windows with Python 3.10 and PyAV 17. I haven't run it on Linux or macOS, or with a real
ffmpegpipe, sinceffmpegisn't installed on my machine. The tests pipe the file's bytes directly.