mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
Merge branch 'develop' into bugfix/fps_retime_rounding_issue
This commit is contained in:
commit
0b2580bc63
6 changed files with 165 additions and 71 deletions
|
|
@ -15,7 +15,7 @@ from ayon_core.pipeline.plugin_discover import (
|
|||
deregister_plugin,
|
||||
deregister_plugin_path
|
||||
)
|
||||
from ayon_core.pipeline import get_staging_dir_info
|
||||
from ayon_core.pipeline.staging_dir import get_staging_dir_info, StagingDir
|
||||
|
||||
from .constants import DEFAULT_VARIANT_VALUE
|
||||
from .product_name import get_product_name
|
||||
|
|
@ -833,7 +833,7 @@ class Creator(BaseCreator):
|
|||
"""
|
||||
return self.pre_create_attr_defs
|
||||
|
||||
def get_staging_dir(self, instance):
|
||||
def get_staging_dir(self, instance) -> Optional[StagingDir]:
|
||||
"""Return the staging dir and persistence from instance.
|
||||
|
||||
Args:
|
||||
|
|
@ -915,7 +915,7 @@ class Creator(BaseCreator):
|
|||
|
||||
instance.transient_data.update({
|
||||
"stagingDir": staging_dir_path,
|
||||
"stagingDir_persistent": staging_dir_info.persistent,
|
||||
"stagingDir_persistent": staging_dir_info.is_persistent,
|
||||
})
|
||||
|
||||
self.log.info(f"Applied staging dir to instance: {staging_dir_path}")
|
||||
|
|
|
|||
|
|
@ -238,10 +238,13 @@ def remap_range_on_file_sequence(otio_clip, otio_range):
|
|||
# source range for image sequence. Following code maintain
|
||||
# backward-compatibility by adjusting media_in
|
||||
# while we are updating those.
|
||||
conformed_src_in = source_range.start_time.rescaled_to(
|
||||
available_range_rate
|
||||
)
|
||||
if (
|
||||
is_clip_from_media_sequence(otio_clip)
|
||||
and available_range_start_frame == media_ref.start_frame
|
||||
and source_range.start_time.to_frames() < media_ref.start_frame
|
||||
and conformed_src_in.to_frames() < media_ref.start_frame
|
||||
):
|
||||
media_in = otio.opentime.RationalTime(
|
||||
0, rate=available_range_rate
|
||||
|
|
@ -272,21 +275,6 @@ def get_media_range_with_retimes(otio_clip, handle_start, handle_end):
|
|||
media_ref = otio_clip.media_reference
|
||||
is_input_sequence = is_clip_from_media_sequence(otio_clip)
|
||||
|
||||
# Temporary.
|
||||
# Some AYON custom OTIO exporter were implemented with relative
|
||||
# source range for image sequence. Following code maintain
|
||||
# backward-compatibility by adjusting available range
|
||||
# while we are updating those.
|
||||
if (
|
||||
is_input_sequence
|
||||
and available_range.start_time.to_frames() == media_ref.start_frame
|
||||
and source_range.start_time.to_frames() < media_ref.start_frame
|
||||
):
|
||||
available_range = _ot.TimeRange(
|
||||
_ot.RationalTime(0, rate=available_range_rate),
|
||||
available_range.duration,
|
||||
)
|
||||
|
||||
# Conform source range bounds to available range rate
|
||||
# .e.g. embedded TC of (3600 sec/ 1h), duration 100 frames
|
||||
#
|
||||
|
|
@ -331,6 +319,22 @@ def get_media_range_with_retimes(otio_clip, handle_start, handle_end):
|
|||
else:
|
||||
conformed_source_range = source_range
|
||||
|
||||
# Temporary.
|
||||
# Some AYON custom OTIO exporter were implemented with relative
|
||||
# source range for image sequence. Following code maintain
|
||||
# backward-compatibility by adjusting available range
|
||||
# while we are updating those.
|
||||
if (
|
||||
is_input_sequence
|
||||
and available_range.start_time.to_frames() == media_ref.start_frame
|
||||
and conformed_source_range.start_time.to_frames() <
|
||||
media_ref.start_frame
|
||||
):
|
||||
available_range = _ot.TimeRange(
|
||||
_ot.RationalTime(0, rate=available_range_rate),
|
||||
available_range.duration,
|
||||
)
|
||||
|
||||
# modifiers
|
||||
time_scalar = 1.
|
||||
offset_in = 0
|
||||
|
|
|
|||
|
|
@ -716,8 +716,8 @@ def get_instance_staging_dir(instance):
|
|||
os.makedirs(staging_dir_path, exist_ok=True)
|
||||
instance.data.update({
|
||||
"stagingDir": staging_dir_path,
|
||||
"stagingDir_persistent": staging_dir_info.persistent,
|
||||
"stagingDir_custom": staging_dir_info.custom
|
||||
"stagingDir_persistent": staging_dir_info.is_persistent,
|
||||
"stagingDir_is_custom": staging_dir_info.is_custom
|
||||
})
|
||||
|
||||
return staging_dir_path
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
import logging
|
||||
import warnings
|
||||
from typing import Optional, Dict, Any
|
||||
from dataclasses import dataclass
|
||||
|
||||
from ayon_core.lib import Logger, filter_profiles
|
||||
|
|
@ -11,21 +14,41 @@ from .tempdir import get_temp_dir
|
|||
@dataclass
|
||||
class StagingDir:
|
||||
directory: str
|
||||
persistent: bool
|
||||
custom: bool # Whether the staging dir is a custom staging dir
|
||||
is_persistent: bool
|
||||
# Whether the staging dir is a custom staging dir
|
||||
is_custom: bool
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
if key == "persistent":
|
||||
warnings.warn(
|
||||
"'StagingDir.persistent' is deprecated."
|
||||
" Use 'StagingDir.is_persistent' instead.",
|
||||
DeprecationWarning
|
||||
)
|
||||
key = "is_persistent"
|
||||
super().__setattr__(key, value)
|
||||
|
||||
@property
|
||||
def persistent(self):
|
||||
warnings.warn(
|
||||
"'StagingDir.persistent' is deprecated."
|
||||
" Use 'StagingDir.is_persistent' instead.",
|
||||
DeprecationWarning
|
||||
)
|
||||
return self.is_persistent
|
||||
|
||||
|
||||
def get_staging_dir_config(
|
||||
project_name,
|
||||
task_type,
|
||||
task_name,
|
||||
product_type,
|
||||
product_name,
|
||||
host_name,
|
||||
project_settings=None,
|
||||
anatomy=None,
|
||||
log=None,
|
||||
):
|
||||
project_name: str,
|
||||
task_type: Optional[str],
|
||||
task_name: Optional[str],
|
||||
product_type: str,
|
||||
product_name: str,
|
||||
host_name: str,
|
||||
project_settings: Optional[Dict[str, Any]] = None,
|
||||
anatomy: Optional[Anatomy] = None,
|
||||
log: Optional[logging.Logger] = None,
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""Get matching staging dir profile.
|
||||
|
||||
Args:
|
||||
|
|
@ -76,7 +99,6 @@ def get_staging_dir_config(
|
|||
|
||||
# get template from template name
|
||||
template_name = profile["template_name"]
|
||||
_validate_template_name(project_name, template_name, anatomy)
|
||||
|
||||
template = anatomy.get_template_item("staging", template_name)
|
||||
|
||||
|
|
@ -93,35 +115,22 @@ def get_staging_dir_config(
|
|||
return {"template": template, "persistence": data_persistence}
|
||||
|
||||
|
||||
def _validate_template_name(project_name, template_name, anatomy):
|
||||
"""Check that staging dir section with appropriate template exist.
|
||||
|
||||
Raises:
|
||||
ValueError - if misconfigured template
|
||||
"""
|
||||
if template_name not in anatomy.templates["staging"]:
|
||||
raise ValueError(
|
||||
f'Anatomy of project "{project_name}" does not have set'
|
||||
f' "{template_name}" template key at Staging Dir category!'
|
||||
)
|
||||
|
||||
|
||||
def get_staging_dir_info(
|
||||
project_entity,
|
||||
folder_entity,
|
||||
task_entity,
|
||||
product_type,
|
||||
product_name,
|
||||
host_name,
|
||||
anatomy=None,
|
||||
project_settings=None,
|
||||
template_data=None,
|
||||
always_return_path=True,
|
||||
force_tmp_dir=False,
|
||||
logger=None,
|
||||
prefix=None,
|
||||
suffix=None,
|
||||
):
|
||||
project_entity: Dict[str, Any],
|
||||
folder_entity: Optional[Dict[str, Any]],
|
||||
task_entity: Optional[Dict[str, Any]],
|
||||
product_type: str,
|
||||
product_name: str,
|
||||
host_name: str,
|
||||
anatomy: Optional[Anatomy] = None,
|
||||
project_settings: Optional[Dict[str, Any]] = None,
|
||||
template_data: Optional[Dict[str, Any]] = None,
|
||||
always_return_path: bool = True,
|
||||
force_tmp_dir: bool = False,
|
||||
logger: Optional[logging.Logger] = None,
|
||||
prefix: Optional[str] = None,
|
||||
suffix: Optional[str] = None,
|
||||
) -> Optional[StagingDir]:
|
||||
"""Get staging dir info data.
|
||||
|
||||
If `force_temp` is set, staging dir will be created as tempdir.
|
||||
|
|
@ -161,11 +170,15 @@ def get_staging_dir_info(
|
|||
)
|
||||
|
||||
if force_tmp_dir:
|
||||
return get_temp_dir(
|
||||
project_name=project_entity["name"],
|
||||
anatomy=anatomy,
|
||||
prefix=prefix,
|
||||
suffix=suffix,
|
||||
return StagingDir(
|
||||
get_temp_dir(
|
||||
project_name=project_entity["name"],
|
||||
anatomy=anatomy,
|
||||
prefix=prefix,
|
||||
suffix=suffix,
|
||||
),
|
||||
is_persistent=False,
|
||||
is_custom=False
|
||||
)
|
||||
|
||||
# making few queries to database
|
||||
|
|
@ -205,8 +218,8 @@ def get_staging_dir_info(
|
|||
dir_template = staging_dir_config["template"]["directory"]
|
||||
return StagingDir(
|
||||
dir_template.format_strict(ctx_data),
|
||||
persistent=staging_dir_config["persistence"],
|
||||
custom=True
|
||||
is_persistent=staging_dir_config["persistence"],
|
||||
is_custom=True
|
||||
)
|
||||
|
||||
# no config found but force an output
|
||||
|
|
@ -218,8 +231,8 @@ def get_staging_dir_info(
|
|||
prefix=prefix,
|
||||
suffix=suffix,
|
||||
),
|
||||
persistent=False,
|
||||
custom=False
|
||||
is_persistent=False,
|
||||
is_custom=False
|
||||
)
|
||||
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"OTIO_SCHEMA": "Clip.2",
|
||||
"metadata": {},
|
||||
"name": "",
|
||||
"source_range": {
|
||||
"OTIO_SCHEMA": "TimeRange.1",
|
||||
"duration": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 23.976,
|
||||
"value": 108.0
|
||||
},
|
||||
"start_time": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 23.976,
|
||||
"value": 883159.0
|
||||
}
|
||||
},
|
||||
"effects": [],
|
||||
"markers": [],
|
||||
"enabled": true,
|
||||
"media_references": {
|
||||
"DEFAULT_MEDIA": {
|
||||
"OTIO_SCHEMA": "ImageSequenceReference.1",
|
||||
"metadata": {},
|
||||
"name": "",
|
||||
"available_range": {
|
||||
"OTIO_SCHEMA": "TimeRange.1",
|
||||
"duration": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 24.0,
|
||||
"value": 755.0
|
||||
},
|
||||
"start_time": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 24.0,
|
||||
"value": 883750.0
|
||||
}
|
||||
},
|
||||
"available_image_bounds": null,
|
||||
"target_url_base": "/mnt/jobs/yahoo_theDog_1132/IN/FOOTAGE/SCANS_LINEAR/Panasonic Rec 709 to ACESCG/Panasonic P2 /A001_S001_S001_T004/",
|
||||
"name_prefix": "A001_S001_S001_T004.",
|
||||
"name_suffix": ".exr",
|
||||
"start_frame": 883750,
|
||||
"frame_step": 1,
|
||||
"rate": 1.0,
|
||||
"frame_zero_padding": 0,
|
||||
"missing_frame_policy": "error"
|
||||
}
|
||||
},
|
||||
"active_media_reference_key": "DEFAULT_MEDIA"
|
||||
}
|
||||
|
|
@ -209,3 +209,29 @@ def test_img_sequence_conform_to_23_976fps():
|
|||
handle_start=0,
|
||||
handle_end=8,
|
||||
)
|
||||
|
||||
|
||||
def test_img_sequence_conform_from_24_to_23_976fps():
|
||||
"""
|
||||
Img sequence clip
|
||||
available files = 883750-884504 24fps
|
||||
source_range = 883159-883267 23.976fps
|
||||
|
||||
This test ensures such entries do not trigger
|
||||
the legacy Hiero export compatibility.
|
||||
"""
|
||||
expected_data = {
|
||||
'mediaIn': 884043,
|
||||
'mediaOut': 884150,
|
||||
'handleStart': 0,
|
||||
'handleEnd': 0,
|
||||
'speed': 1.0
|
||||
}
|
||||
|
||||
_check_expected_retimed_values(
|
||||
"img_seq_24_to_23.976_no_legacy.json",
|
||||
expected_data,
|
||||
handle_start=0,
|
||||
handle_end=0,
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue