Source code for avfilters.inspect

"""Multimedia files inspection utilities.

This module is currently work in progress.
"""

from dataclasses import dataclass
from fractions import Fraction
from typing import Iterable, Iterator, List

import av


[docs] @dataclass class Codec: # TODO: complete missing fields """A codec. Dataclass version of :class:`av.Codec`. """ name: str """The codec name."""
[docs] @classmethod def from_av_codec(cls, codec: av.Codec) -> "Codec": """Create a codec dataclass from a PyAV codec. Args: codec: The PyAV codec. Return: The corresponding codec dataclass. """ return cls(name=codec.name)
[docs] @dataclass class CodecContext: # TODO: complete missing fields """A codec context. Dataclass version of :class:`av.codec.context.CodecContext`. """ codec: Codec """The codec."""
[docs] @classmethod def from_av_codec_context( cls, codec_context: av.codec.context.CodecContext ) -> "CodecContext": """Create a codec context dataclass from a PyAV codec context. Args: codec_context: The PyAV codec context. Return: The corresponding codec context dataclass. """ return cls(codec=Codec.from_av_codec(codec_context.codec))
[docs] @dataclass class Stream: """A single stream of audio, video or subtitles within a Container. Dataclass version of :class:`av.stream.Stream`. """ averaged_rate: Fraction """The average frame rate of this video stream. See :attr:`av.stream.Stream.averaged_rate`. """ base_rate: Fraction codec_context: CodecContext duration: float frames: int guessed_rate: Fraction index: int language: str metadata: dict profile: str start_time: str time_base: Fraction type: str """The type of the stream. See :attr:`av.stream.Stream.type`. """
[docs] @classmethod def from_av_stream(cls, stream: av.stream.Stream) -> "Stream": """Create a stream dataclass from a PyAV stream. Args: stream: The PyAV stream. Return: The corresponding stream dataclass. """ return cls( averaged_rate=stream.base_rate, base_rate=stream.base_rate, codec_context=CodecContext.from_av_codec_context(stream.codec_context), duration=stream.duration, frames=stream.frames, guessed_rate=stream.guessed_rate, index=stream.index, language=stream.language, metadata=stream.metadata, profile=stream.profile, start_time=stream.start_time, time_base=stream.time_base, type=stream.type, )
@property def duration_seconds(self) -> float: """Return the duration of this stream in seconds. Return: The duration of this stream in seconds. """ return float(self.duration * self.time_base)
[docs] @dataclass class Container: """A multimedia container. Dataclass version of :class:`av.container.Container`. """ """ The list of streams in this container. """ streams: List[Stream] def __getitem__(self, key: int) -> Stream: """Return the stream at a given index. Args: key: The index of the stream. Return: The corresponding stream. """ return self.streams[key] def __iter__(self) -> Iterator[Stream]: """Return an iterator over this container's streams. Return: An iterator over this container's streams. """ return iter(self.streams) def __len__(self) -> int: """Return the number of streams in this container. Return: The number of streams. """ return len(self.streams)
[docs] @classmethod def from_file(cls, file: str) -> "Container": """Create a container dataclass from a multimedia file. Args: file: The multimedia file. Return: The corresponding container dataclass. """ with av.open(file) as container: return Container.from_av_container(container)
[docs] @classmethod def from_av_container(cls, container: av.container.Container) -> "Container": """Create a container from a PyAV container. Args: container: The PyAV container. Return: The corresponding container dataclass. """ return cls( streams=[Stream.from_av_stream(stream) for stream in container.streams] )
[docs] def inspect(file: str) -> Container: """Inpsect a multimedia file container. Args: file: The multimedia file. Return: The corresponding container dataclass. """ return Container.from_file(file)
[docs] def filter_out_no_stream(files: Iterable[str]) -> Iterator[str]: """Return a iterator that excludes files with no stream. Args: files: The multimedia files. Return: The files that have at least one stream. """ for file in files: with av.open(file) as container: if len(container.streams) > 0: yield file