Skip to content

#841 Track range_of_all_children applies TimeEffect effect to duratio…#842

Open
splidje wants to merge 7 commits into
AcademySoftwareFoundation:mainfrom
splidje:fix/otioview_timewarp
Open

#841 Track range_of_all_children applies TimeEffect effect to duratio…#842
splidje wants to merge 7 commits into
AcademySoftwareFoundation:mainfrom
splidje:fix/otioview_timewarp

Conversation

@splidje

@splidje splidje commented Dec 10, 2020

Copy link
Copy Markdown
Contributor

Fixes #841

Track range_of_all_children applies TimeEffect effect to duration of clip.

@reinecke reinecke left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @splidje,
Thanks for jumping in!

I think there is some misleading terminology in OTIO when TimeWarp is applied to a clip. Here is the code in python I use if I have a clip in a timeline that has a LinearTimeWarp applied and I want to calculate the original source frame range:

time_warps = [
    effect for effect in clip.effects
    if isinstance(effect, otio.schema.LinearTimeWarp)
]
time_scalar = functools.reduce(
    lambda x, y: (x * y.time_scalar if y.time_scalar != 0 else 0),
    time_warps,
    1,
 )
effect_transform = otio.opentime.TimeTransform(scale=time_scalar)

 computed_duration = effect_transform.applied_to(clip.source_range.duration)

This works well with EDLs I've been using. The way I think of it is that the retimed clip is acting like it's own new piece of media and if you want to evaluate the range in the original media you have to do so backwards through the time warps.

@ssteinbach @meshula @jminor Would you mind checking my mental model on this stuff, I've always been a little fuzzy about the mental model for TimeWarps.

Depending on the answer to that, if we decide to move forward we'd want to have some unittesting in place before accepting the PR.

Comment thread src/opentimelineio/linearTimeWarp.h Outdated
}

virtual TimeRange output_range(TimeRange input_range, ErrorStatus* error_status) const {
return TimeRange(input_range.start_time(), input_range.duration() / _time_scalar);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you could construct aTimeTransform and then use .applied_to(input_range.duration() to compute the scaled duration.

Also, another thing to consider is what happens when _time_scalar is zero (like for FreezeFrame). Perhaps, if it doesn't exist, a unittest for the FreezeFame case should be added.

friend RationalTime operator/ (RationalTime lhs, double rhs) {
return RationalTime {lhs._value / rhs, lhs._rate};
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We originally omitted overloading / and * operators for RationalTIme because we felt that the meaning of division and multiplication in the context of RationalTime could potentially be ambiguous. Instead we provided TimeTransform to make sure it was explicit how these operations work.

Comment thread src/opentimelineio/track.cpp Outdated
}
else if (auto item = dynamic_cast<Item*>(child.value)) {
auto last_range = TimeRange(last_end_time, item->trimmed_range(error_status).duration());
auto output_range = TimeRange(RationalTime(0), item->trimmed_range(error_status).duration());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since considerable work is potentially being done in the following for loop, should error_status be right after instead of later below?

@splidje

splidje commented Dec 11, 2020

Copy link
Copy Markdown
Contributor Author

Thank you for the review. I wasn't aware of TimeTransform. I'll make those changes.

It makes sense in my head that a clip has source_range referring to the section of the source media to use, and then any number of time effects, each mapping output time to source time. So you can concatenate them all to form an effective mapping from output time to source time. Also part of that transform can helpfully tell you what the domain of the mapping is with a given range.

if you had the mapping (output -> source):
1 -> 5
2 -> 0
3 -> 3
and the source range was 0-5, then the output range would be 1-3. Then when actually trying to produce a frame, we know that the clip effectively has the "source range" 1-3, we ask it for the first frame: 1, the time effect maps that to 5 in order to address the source media.

@splidje

splidje commented Dec 11, 2020

Copy link
Copy Markdown
Contributor Author

I'm probably being naive though. As you say, freeze frame is an anomaly. Should it be separate from a time effect as it has special behaviour, or should time effect be designed to encompass freeze frame? Not sure.

A freeze frame needs a duration. Actually, it's just occurred to me that it does fit the model I described above. A time effect provides two things:

  1. mapping from output time to source time
  2. effective duration

so a freeze frame would just return its duration property for duration, and the mapping always returns the same source frame.

@codecov-io

codecov-io commented Dec 11, 2020

Copy link
Copy Markdown

Codecov Report

Merging #842 (67046c5) into master (5aa24fb) will decrease coverage by 0.34%.
The diff coverage is 23.52%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #842      +/-   ##
==========================================
- Coverage   84.18%   83.84%   -0.35%     
==========================================
  Files          74       74              
  Lines        3061     3076      +15     
==========================================
+ Hits         2577     2579       +2     
- Misses        484      497      +13     
Flag Coverage Δ
unittests 83.84% <23.52%> (-0.35%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/opentimelineio/linearTimeWarp.h 50.00% <0.00%> (-50.00%) ⬇️
src/opentimelineio/timeEffect.cpp 57.14% <0.00%> (-42.86%) ⬇️
...entimelineio-bindings/otio_serializableObjects.cpp 94.64% <33.33%> (-0.48%) ⬇️
src/opentimelineio/track.cpp 88.76% <42.85%> (-4.10%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5aa24fb...67046c5. Read the comment docs.

…imeEffect to differentiate it from LinearTimeWarp. Given it a duration property.
…uration in a track. So a TimeEffect actually has no effect on changing an item's duration. I still have FreezeFrame as a direct subclass of TimeEffect, rather than LinearTimeWarp - it doesn't need a time_scalar property of 0, we know that already about it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants