Skip to content

Commit

Permalink
[cli] Add new export-qp command (#388)
Browse files Browse the repository at this point in the history
  • Loading branch information
Breakthrough committed Sep 30, 2024
1 parent ded3708 commit be668d9
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 13 deletions.
48 changes: 35 additions & 13 deletions scenedetect/_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ def scenedetect(
)
@click.pass_context
def help_command(ctx: click.Context, command_name: str):
"""Print help for command (`help [command]`)."""
"""Print full help reference."""
assert isinstance(ctx.parent.command, click.MultiCommand)
parent_command = ctx.parent.command
all_commands = set(parent_command.list_commands(ctx))
Expand Down Expand Up @@ -1442,30 +1442,52 @@ def save_images_command(
ctx.save_images = True


@click.command("export-qp", cls=_Command)
@click.option(
"--filename",
"-f",
metavar="NAME",
default=None,
type=click.STRING,
help="Filename format to use. %s" % (USER_CONFIG.get_help_string("export-qp", "filename")),
)
@click.pass_context
def export_qp_command(
ctx: click.Context,
filename: ty.Optional[ty.AnyStr],
):
ctx = ctx.obj
assert isinstance(ctx, CliContext)

export_qp_args = {
"filename_format": ctx.config.get_value("save-images", "filename", filename),
}
ctx.add_command(cli_commands.export_qp, export_qp_args)


# ----------------------------------------------------------------------
# Commands Omitted From Help List
# CLI Sub-Command Registration
# ----------------------------------------------------------------------

# Info Commands
# Informational
scenedetect.add_command(about_command)
scenedetect.add_command(help_command)
scenedetect.add_command(version_command)

# ----------------------------------------------------------------------
# Commands Added To Help List
# ----------------------------------------------------------------------

# Input / Output
scenedetect.add_command(export_html_command)
scenedetect.add_command(list_scenes_command)
# Input
scenedetect.add_command(load_scenes_command)
scenedetect.add_command(save_images_command)
scenedetect.add_command(split_video_command)
scenedetect.add_command(time_command)

# Detection Algorithms
# Detectors
scenedetect.add_command(detect_adaptive_command)
scenedetect.add_command(detect_content_command)
scenedetect.add_command(detect_hash_command)
scenedetect.add_command(detect_hist_command)
scenedetect.add_command(detect_threshold_command)

# Output
scenedetect.add_command(export_html_command)
scenedetect.add_command(export_qp_command)
scenedetect.add_command(list_scenes_command)
scenedetect.add_command(save_images_command)
scenedetect.add_command(split_video_command)
21 changes: 21 additions & 0 deletions scenedetect/_cli/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,27 @@ def export_html(
)


def export_qp(
context: CliContext,
scenes: SceneList,
cuts: CutList,
filename_format: str,
):
"""Handler for the `export-qp` command."""
del scenes # We only use cuts for this handler.

qp_path = Template(filename_format).safe_substitute(VIDEO_NAME=context.video_stream.name)
with open(qp_path, "w") as qp_file:
# TODO(#388): Instead of setting start time, should we always start at 0 and shift each
# cut by the amount that was seeked?
first_frame = 0 if context.start_time is None else context.start_time.frame_num
# Place an initial I frame at the first frame.
qp_file.writelines([f"{first_frame} I -1"])
# Place another I frame at each detected cut.
qp_file.writelines(f"{cut.frame_num} I -1" for cut in cuts)
logger.info(f"QP file written to: {qp_path}")


def list_scenes(
context: CliContext,
scenes: SceneList,
Expand Down
3 changes: 3 additions & 0 deletions scenedetect/_cli/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,9 @@ def format(self, timecode: FrameTimecode) -> str:
"image-width": 0,
"no-images": False,
},
"export-qp": {
"filename": "$VIDEO_NAME.qp",
},
"list-scenes": {
"cut-format": "timecode",
"display-cuts": True,
Expand Down
13 changes: 13 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,19 @@ def test_cli_export_html(tmp_path: Path):
# TODO: Check for existence of HTML & image files.


def test_cli_export_qp(tmp_path: Path):
"""Test `export-qp` command."""
base_command = "-i {VIDEO} -s {STATS} time {TIME} {DETECTOR} {COMMAND}"
assert invoke_scenedetect(base_command, COMMAND="export-qp", output_dir=tmp_path) == 0
assert (
invoke_scenedetect(
base_command, COMMAND="export-qp --filename custom.txt", output_dir=tmp_path
)
== 0
)
# TODO: Check for existence of QP files.


@pytest.mark.parametrize("backend_type", ALL_BACKENDS)
def test_cli_backend(backend_type: str):
"""Test setting the `-b`/`--backend` argument."""
Expand Down

0 comments on commit be668d9

Please sign in to comment.