| #!/usr/bin/env python3 | |
| ## Copyright (c) 2023, Alliance for Open Media. All rights reserved | |
| ## | |
| ## This source code is subject to the terms of the BSD 3-Clause Clear License and the | |
| ## Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear License was | |
| ## not distributed with this source code in the LICENSE file, you can obtain it | |
| ## at aomedia.org/license/software-license/bsd-3-c-c/. If the Alliance for Open Media Patent | |
| ## License 1.0 was not distributed with this source code in the PATENTS file, you | |
| ## can obtain it at aomedia.org/license/patent-license/. | |
| ## | |
| """Wrapper around the extract_proto binary.""" | |
| from collections.abc import Sequence | |
| import dataclasses | |
| import os | |
| import pathlib | |
| import subprocess | |
| from typing import Iterator | |
| from absl import logging | |
| from avm_stats import avm_frame_pb2 | |
| from avm_stats import proto_helpers | |
| @dataclasses.dataclass | |
| class ExtractProtoResult: | |
| output_path: pathlib.Path | |
| proto_count: int | |
| skipped: bool | |
| stdout: str | None = None | |
| stderr: str | None = None | |
| def _count_protos(proto_dir: pathlib.Path) -> int: | |
| return sum([1 for _ in proto_dir.glob("*.pb")]) | |
| def extract_proto( | |
| *, | |
| extract_proto_path: pathlib.Path, | |
| stream_path: pathlib.Path, | |
| output_path: pathlib.Path, | |
| skip_if_output_already_exists: bool = False, | |
| yuv_path: pathlib.Path | None = None, | |
| frame_limit: int | None = None, | |
| extra_args: list[str] | None = None | |
| ) -> ExtractProtoResult: | |
| if ( | |
| skip_if_output_already_exists | |
| and os.path.exists(output_path) | |
| and os.path.isdir(output_path) | |
| ): | |
| count = _count_protos(output_path) | |
| if count > 0: | |
| logging.info( | |
| "%s already exists, skipping extract_proto.", str(output_path) | |
| ) | |
| return ExtractProtoResult( | |
| output_path=output_path, proto_count=count, skipped=True | |
| ) | |
| os.makedirs(output_path, exist_ok=True) | |
| extract_proto_args = [ | |
| str(extract_proto_path), | |
| "--stream", | |
| str(stream_path), | |
| "--output_folder", | |
| str(output_path), | |
| ] | |
| if yuv_path is not None: | |
| extract_proto_args.extend([ | |
| "--orig_yuv", | |
| str(yuv_path), | |
| ]) | |
| if frame_limit is not None: | |
| extract_proto_args.extend([ | |
| "--limit", | |
| str(frame_limit), | |
| ]) | |
| if extra_args is not None: | |
| extract_proto_args.extend(extra_args) | |
| logging.info("Running:\n %s", " ".join(extract_proto_args)) | |
| p = subprocess.run(extract_proto_args, capture_output=True, check=True) | |
| stdout = p.stdout.decode("utf-8") | |
| stdin = p.stderr.decode("utf-8") | |
| count = _count_protos(output_path) | |
| return ExtractProtoResult( | |
| output_path=output_path, | |
| proto_count=count, | |
| skipped=False, | |
| stdout=stdout, | |
| stderr=stdin, | |
| ) | |
| def load_protos(proto_dir: pathlib.Path) -> Iterator[proto_helpers.Frame]: | |
| # Note: Sorting is important here, since the proto file names are numbered in | |
| # decode order, but glob returns files in arbitrary order. | |
| for pb in sorted(proto_dir.glob("*.pb")): | |
| with open(pb, "rb") as f: | |
| frame_proto = avm_frame_pb2.Frame.FromString(f.read()) | |
| frame = proto_helpers.Frame(frame_proto) | |
| yield frame | |
| def extract_and_load_protos( | |
| *, | |
| extract_proto_path: pathlib.Path, | |
| stream_path: pathlib.Path, | |
| output_path: pathlib.Path, | |
| skip_if_output_already_exists: bool = False, | |
| yuv_path: pathlib.Path | None = None, | |
| frame_limit: int | None = None, | |
| extra_args: list[str] | None = None | |
| ) -> Iterator[proto_helpers.Frame]: | |
| result = extract_proto( | |
| extract_proto_path=extract_proto_path, | |
| stream_path=stream_path, | |
| output_path=output_path, | |
| skip_if_output_already_exists=skip_if_output_already_exists, | |
| yuv_path=yuv_path, | |
| frame_limit=frame_limit, | |
| extra_args=extra_args, | |
| ) | |
| yield from load_protos(result.output_path) |