AAF Parser - Calculating Source Values#1063
AAF Parser - Calculating Source Values#1063andrewmoore-nz wants to merge 1 commit intoAcademySoftwareFoundation:mainfrom
Conversation
…utine for investigation and discussion with the group.
|
This approach directly addresses the the situation I outlined in my issue from 2019 - #523 An example of how/why this approach is needed... when a |
|
@andrewmoore-nz are you still on this issue? |
|
@timlehr This pull request was supposed to be a jumping off point to look at addressing the AAF parsing issues present in the current version of the parser, which we have fixed in the version currently being used in Matchbox. I'm still very keen to get these changes rolled in. |
|
@jminor @reinecke What needs to happen to get some traction on this? It's been well over two years since Roger Sacilotto confirmed in our call with him that this is the correct approach, so would be great to actually get this rolled in and available for people to use, and some further development can continue. |
|
Hi! I've tagged this for TSC review. Up until now it's been marked as a Draft/Work In Progress, so I've changed the status to Open. I think the core fix in this PR is this: If there was a test case added around this that fails with the existing code, but accepts with the patch, I think we'll be good to go. |
|
@meshula There are a few test clips from back in 2019 that should cover that test case pretty easily so I'll add that to the PR this weekend when I get a chance to look at it again. This was marked as a Draft/Work in Progress as that's what it is meant to be. We had a call back in September discussing this topic, and this Draft PR was supposed to be a jumping off point for a discussion about the problem, which never happened. If this PR specifically was going to be merged, it will need some further work to clean up other, now redundant, parts of the code. |
|
Gotcha, I understood your question on getting traction to mean specifically this PR, as opposed to re-starting a conversation. |
jminor
left a comment
There was a problem hiding this comment.
At a high level this all makes sense. I can't claim that I understand all the details, but I trust that if this passes the unit tests, especially for the wider range of sample AAFs that you have, then this is a nice step forwards.
Sorry for the extremely long delay before looking at it in detail.
| time_effect = op_stack.effects[0] if len(op_stack.effects) > 0 else None | ||
|
|
||
| time_scalar = time_effect.time_scalar if hasattr(time_effect, 'time_scalar') else None | ||
| if time_scalar: |
There was a problem hiding this comment.
Are you checking for None or 0 or both? If it was a freeze frame, the time_scalar will be 0 which Python treats as false.
There was a problem hiding this comment.
0 would only come up via a FreezeFrame. If that was the case, we should already have the right first frame. So 0 and None should both skip this code block.
WBN to have a unit test for that, or at least verify manually to confirm this.
| alt = alt[0] if len(alt) > 0 else None | ||
| if alt is not None: | ||
| return _find_source_clip(item.alternates.value[0], op_group_found) | ||
| # return _find_source_clip(item.selected.value, op_group_found) |
There was a problem hiding this comment.
If alt was None, this should return something. Also, should the Selector's "Selected" item be used here instead of the first alternate?
jminor
left a comment
There was a problem hiding this comment.
If you could turn some of these informal code review notes from our video conf into comments in the code that would be great.
| mobs.append(mob) | ||
| else: | ||
| continue | ||
| def _find_source_clip(item, op_group_found=None): |
There was a problem hiding this comment.
From Zoom code review: we're wondering what item is passed in here?
There was a problem hiding this comment.
This was the segment of the 1st slot of the source clip from _find_mob_chain_and_timecode, which might just be a SourceClip, but we might need to dig into the structure under it to find the SourceClip.
There was a problem hiding this comment.
This if/elif chain is attempting to handle the variety of AAFs in our test suite (both in OTIO, and from Matchbox) but we are still unclear of the full breadth of structures we might find within a SourceClip.
| return None | ||
| slot = [s for s in mob.slots if s.slot_id == slot_id] | ||
| slot = slot[0] if len(slot) > 0 else None | ||
| result = _find_source_clip(slot.segment) if slot else (None, None) |
There was a problem hiding this comment.
From Zoom code review: this is where the code attempts to drill into the SourceClip to find the details of what's inside it
|
|
||
| source_start = int(metadata.get("StartTime", "0")) | ||
| if source_start_multiplier: | ||
| source_start = int(source_start * source_start_multiplier) |
There was a problem hiding this comment.
Is the multiplier just from varying frame rate clips, or is this from timewarp effects in the composition?
0 or None means it was not found, and should be ignored.
| time_effect = op_stack.effects[0] if len(op_stack.effects) > 0 else None | ||
|
|
||
| time_scalar = time_effect.time_scalar if hasattr(time_effect, 'time_scalar') else None | ||
| if time_scalar: |
There was a problem hiding this comment.
0 would only come up via a FreezeFrame. If that was the case, we should already have the right first frame. So 0 and None should both skip this code block.
WBN to have a unit test for that, or at least verify manually to confirm this.
| time_effect = op_stack.effects[0] if len(op_stack.effects) > 0 else None | ||
|
|
||
| time_scalar = time_effect.time_scalar if hasattr(time_effect, 'time_scalar') else None | ||
| if time_scalar: |
There was a problem hiding this comment.
| if time_scalar: | |
| if time_scalar is �None or time_scalar == 0: # FreezeFrames have a time_scale of 0 |
|
I think we can close this one in favour of OpenTimelineIO/otio-aaf-adapter#44. |
|
Closing in favor of OpenTimelineIO/otio-aaf-adapter#44 |
Following on from this weeks AAF call, this is the main process being used to correctly calculate the source timecode values for the SourceClip component.
@jminor @timlehr @stefanschulze
To give a brief recap, the source timecode values are calculated by looking at a chain of Media Objects (Mobs) and summing and converting a selection of values. The chain of mobs will be a combination of CompositionMobs, MasterMobs, and SourceMobs. There can be a source clip Origin, source clip Start, and a mob slot timecode object, all of which can effect the frame count that ends up being the source start value.
The function
_find_mob_chain_and_timecode()condenses a few things in to one process for efficiency:Because all the relevant media objects for this particular source clip are returned from this process, there are several efficiencies that can be gained further on in this part of the
_transcribe()function. I haven't included any of those here though, as I just want to focus on the source timecode values for now. I can't completely separate the pull requests, as the further changes are reliant on those mobs being available in that particular way.This