Skip to content

y5gfunc.source.wobbly.processors.special_frames

special_frames

Special frames processing (frozen frames, decimation).

Classes:

Name Description
FrozenFramesProcessor

Frozen frames processor implementation

DecimationProcessor

Decimation processor implementation

SpecialFrameMarkProcessor

Mark special frames processor implementation

Attributes:

Name Type Description
core

core module-attribute

core = core

FrozenFramesProcessor

FrozenFramesProcessor()

Bases: BaseProcessor

Frozen frames processor implementation

Initialize frozen frames processor

Methods:

Name Description
process

Process frozen frames

Attributes:

Name Type Description
keys
Source code in y5gfunc/source/wobbly/processors/special_frames.py
def __init__(self):
    """Initialize frozen frames processor"""
    self.keys = WobblyKeys()

keys instance-attribute

keys = WobblyKeys()

process

Process frozen frames

Parameters:

Name Type Description Default

clip

VideoNode

Input video clip

required

project

ProjectData

Project data

required

frame_props

FramePropertyMap

Frame property mapping

required

frame_mapping

FrameMap

Frame number mapping

required

presets

PresetDict

Preset function dictionary

required

Returns:

Type Description
tuple[VideoNode, FramePropertyMap, FrameMap]

Processed clip, updated frame properties and frame mapping

Source code in y5gfunc/source/wobbly/processors/special_frames.py
def process(
    self,
    clip: vs.VideoNode,
    project: ProjectData,
    frame_props: FramePropertyMap,
    frame_mapping: FrameMap,
    presets: PresetDict,
) -> tuple[vs.VideoNode, FramePropertyMap, FrameMap]:
    """
    Process frozen frames

    Args:
        clip: Input video clip
        project: Project data
        frame_props: Frame property mapping
        frame_mapping: Frame number mapping
        presets: Preset function dictionary

    Returns:
        Processed clip, updated frame properties and frame mapping
    """
    with safe_processing("frozen_frames_processing"):
        Keys = self.keys
        frozen_frames_list = project.get(Keys.project.frozen_frames, [])

        if not (frozen_frames_list and hasattr(core.std, "FreezeFrames")):
            return clip, frame_props, frame_mapping

        # Gather frame lists
        first_frames = []
        last_frames = []
        replacement_frames = []

        for ff_info in frozen_frames_list:
            if len(ff_info) == 3:
                first, last, replacement = ff_info
                if (
                    0 <= first <= last < clip.num_frames
                    and 0 <= replacement < clip.num_frames
                ):
                    first_frames.append(first)
                    last_frames.append(last)
                    replacement_frames.append(replacement)

                    # Record frozen frame info
                    for i in range(first, last + 1):
                        if i in frame_props:
                            frame_props[i]["WobblyFrozenFrame"] = True
                            frame_props[i]["WobblyFrozenSource"] = replacement

        if first_frames:
            clip = core.std.FreezeFrames(
                clip=clip,
                first=first_frames,
                last=last_frames,
                replacement=replacement_frames,
            )

    return clip, frame_props, frame_mapping

DecimationProcessor

DecimationProcessor()

Bases: BaseProcessor

Decimation processor implementation

Initialize decimation processor

Methods:

Name Description
process

Process frame decimation

Attributes:

Name Type Description
keys
Source code in y5gfunc/source/wobbly/processors/special_frames.py
def __init__(self):
    """Initialize decimation processor"""
    self.keys = WobblyKeys()

keys instance-attribute

keys = WobblyKeys()

process

Process frame decimation

Parameters:

Name Type Description Default

clip

VideoNode

Input video clip

required

project

ProjectData

Project data

required

frame_props

FramePropertyMap

Frame property mapping

required

frame_mapping

FrameMap

Frame number mapping

required

presets

PresetDict

Preset function dictionary

required

Returns:

Type Description
tuple[VideoNode, FramePropertyMap, FrameMap]

Processed clip, updated frame properties and frame mapping

Source code in y5gfunc/source/wobbly/processors/special_frames.py
def process(
    self,
    clip: vs.VideoNode,
    project: ProjectData,
    frame_props: FramePropertyMap,
    frame_mapping: FrameMap,
    presets: PresetDict,
) -> tuple[vs.VideoNode, FramePropertyMap, FrameMap]:
    """
    Process frame decimation

    Args:
        clip: Input video clip
        project: Project data
        frame_props: Frame property mapping
        frame_mapping: Frame number mapping
        presets: Preset function dictionary

    Returns:
        Processed clip, updated frame properties and frame mapping
    """
    with safe_processing("decimation_processing"):
        Keys = self.keys
        decimated_frames_list = project.get(Keys.project.decimated_frames, [])

        if not decimated_frames_list:
            return clip, frame_props, frame_mapping

        # Filter valid frames
        frames_to_delete = [
            f for f in decimated_frames_list if 0 <= f < clip.num_frames
        ]

        if not frames_to_delete:
            return clip, frame_props, frame_mapping

        # Create new frame property map
        new_frame_props: dict[int, dict[str, Any]] = {}
        new_idx = 0

        for n in range(clip.num_frames):
            orig_frame = frame_mapping.get(n, n)

            # If not a frame to delete
            if orig_frame not in frames_to_delete:
                if n in frame_props:
                    new_frame_props[new_idx] = frame_props[n].copy()  # type: ignore[index]
                    new_idx += 1

        # Delete frames
        clip = core.std.DeleteFrames(clip=clip, frames=frames_to_delete)
        frame_props = new_frame_props  # type: ignore[assignment] # Update frame properties

    return clip, frame_props, frame_mapping

SpecialFrameMarkProcessor

SpecialFrameMarkProcessor()

Bases: BaseProcessor

Mark special frames processor implementation

Initialize special frame marker

Methods:

Name Description
process

Mark special frames

Attributes:

Name Type Description
keys
Source code in y5gfunc/source/wobbly/processors/special_frames.py
def __init__(self):
    """Initialize special frame marker"""
    self.keys = WobblyKeys()

keys instance-attribute

keys = WobblyKeys()

process

Mark special frames

Parameters:

Name Type Description Default

clip

VideoNode

Input video clip

required

project

ProjectData

Project data

required

frame_props

FramePropertyMap

Frame property mapping

required

frame_mapping

FrameMap

Frame number mapping

required

presets

PresetDict

Preset function dictionary

required

Returns:

Type Description
tuple[VideoNode, FramePropertyMap, FrameMap]

Processed clip, updated frame properties and frame mapping

Source code in y5gfunc/source/wobbly/processors/special_frames.py
def process(
    self,
    clip: vs.VideoNode,
    project: ProjectData,
    frame_props: FramePropertyMap,
    frame_mapping: FrameMap,
    presets: PresetDict,
) -> tuple[vs.VideoNode, FramePropertyMap, FrameMap]:
    """
    Mark special frames

    Args:
        clip: Input video clip
        project: Project data
        frame_props: Frame property mapping
        frame_mapping: Frame number mapping
        presets: Preset function dictionary

    Returns:
        Processed clip, updated frame properties and frame mapping
    """
    with safe_processing("special_frames_processing"):
        Keys = self.keys
        combed_frames = set(project.get(Keys.project.combed_frames, []))
        decimated_frames = set(project.get(Keys.project.decimated_frames, []))
        matches = self._get_matches_string(project, Keys)
        sections_list = project.get(Keys.project.sections, [])

        # Process Interlaced Fades
        interlaced_fades = project.get(Keys.project.interlaced_fades, [])
        fade_dict = self._process_interlaced_fades(interlaced_fades, Keys)

        # Identify orphan fields
        orphan_fields = self._identify_orphan_fields(
            matches, sections_list, decimated_frames, clip.num_frames, Keys
        )

        # Update special frame properties
        for n in frame_props:
            orig_frame = frame_mapping[n]
            props = frame_props[n]

            # Mark combed frames
            if orig_frame in combed_frames:
                props["WobblyCombed"] = True

            # Mark interlaced fades
            if orig_frame in fade_dict:
                props["WobblyInterlacedFade"] = True
                props["WobblyFieldDifference"] = fade_dict[orig_frame]

            # Mark orphan fields
            if orig_frame in orphan_fields:
                info = orphan_fields[orig_frame]
                props["WobblyOrphan"] = True
                props["WobblyOrphanType"] = info["type"]
                props["WobblyOrphanDecimated"] = info["decimated"]

            # Mark decimated frames
            if orig_frame in decimated_frames:
                props["WobblyDecimated"] = True

    return clip, frame_props, frame_mapping