Source code for megatron.energon.media.metadata

# Copyright (c) 2025, NVIDIA CORPORATION.
# SPDX-License-Identifier: BSD-3-Clause

from __future__ import annotations

import json
from dataclasses import asdict
from enum import Enum
from typing import Any, ClassVar, Dict, Mapping, Type, TypeVar

from megatron.energon.edataclass import edataclass


[docs] class MediaMetadataType(str, Enum): """Enumerates the supported media metadata payload kinds.""" AV = "av" IMAGE = "image"
[docs] @classmethod def from_string(cls, value: str) -> "MediaMetadataType": try: return cls(value) except ValueError as exc: # pragma: no cover - defensive raise ValueError(f"Unsupported media metadata type: {value!r}") from exc
TMetadata = TypeVar("TMetadata", bound="MediaMetadataBase")
[docs] @edataclass class MediaMetadataBase: """Base class for metadata payloads to support typed JSON storage.""" metadata_type: ClassVar[MediaMetadataType]
[docs] def to_dict(self) -> Dict[str, Any]: """Return a JSON-serialisable mapping representation.""" return {key: value for key, value in asdict(self).items() if value is not None}
[docs] @classmethod def from_dict(cls: Type[TMetadata], payload: Mapping[str, Any]) -> TMetadata: """Construct the metadata object from its JSON representation.""" return cls(**payload)
[docs] @edataclass class AVMetadata(MediaMetadataBase): """Metadata of a video or audio asset.""" metadata_type: ClassVar[MediaMetadataType] = MediaMetadataType.AV video_duration: float | None = None video_num_frames: int | None = None video_fps: float | None = None video_width: int | None = None video_height: int | None = None audio_duration: float | None = None audio_channels: int | None = None audio_sample_rate: int | None = None audio_num_samples: int | None = None
[docs] @edataclass class ImageMetadata(MediaMetadataBase): """Metadata for an encoded image file.""" metadata_type: ClassVar[MediaMetadataType] = MediaMetadataType.IMAGE width: int height: int format: str mode: str
_MEDIA_METADATA_REGISTRY: Dict[MediaMetadataType, Type[MediaMetadataBase]] = { MediaMetadataType.AV: AVMetadata, MediaMetadataType.IMAGE: ImageMetadata, }
[docs] def serialize_media_metadata(metadata: MediaMetadataBase) -> tuple[MediaMetadataType, str]: """Serialise the metadata to a tuple of (type, json.dumps(payload)).""" payload_json = json.dumps(metadata.to_dict(), separators=(",", ":")) return metadata.metadata_type, payload_json
[docs] def deserialize_media_metadata( metadata_type: str | MediaMetadataType, metadata_json: str, ) -> MediaMetadataBase: """Deserialize a metadata record from stored SQLite values.""" if not isinstance(metadata_type, MediaMetadataType): metadata_type = MediaMetadataType.from_string(metadata_type) try: payload_cls = _MEDIA_METADATA_REGISTRY[metadata_type] except KeyError as exc: # pragma: no cover - future proofing raise ValueError(f"Unsupported media metadata type: {metadata_type}") from exc payload_dict = json.loads(metadata_json) if metadata_json else {} return payload_cls.from_dict(payload_dict)