2525 import collections .abc as collections_abc
2626except ImportError :
2727 import collections as collections_abc
28- import fractions
2928import opentimelineio as otio
29+ from opentimelineio .opentime import RationalTime
3030
3131lib_path = os .environ .get ("OTIO_AVB_PYTHON_LIB" )
3232if lib_path and lib_path not in sys .path :
@@ -348,16 +348,17 @@ def _walk_reference_chain(item, time, results):
348348 if item is None :
349349 return results
350350
351- results .append ([time , item ])
351+ results .append ([RationalTime ( time , item . edit_rate ) , item ])
352352
353353 if isinstance (item , avb .components .SourceClip ):
354354
355355 mob = item .mob
356356 track = item .track
357357
358358 if track :
359- results .append ([item .start_time + time , mob ])
360- results .append ([item .start_time + time , track ])
359+ r_time = RationalTime (item .start_time + time , item .edit_rate )
360+ results .append ([r_time , mob ])
361+ results .append ([r_time , track ])
361362 # TODO: check for this affects anything
362363 if hasattr (track , 'start_pos' ):
363364 raise AVBAdapterError ("start_pos not handles, sample please" )
@@ -404,15 +405,15 @@ def _walk_reference_chain(item, time, results):
404405
405406 r = _walk_reference_chain (track .component , time , [])
406407 if r and isinstance (r [- 1 ][1 ], avb .components .SourceClip ):
407- results .append ([time , track ])
408+ results .append ([RationalTime ( time , item . edit_rate ) , track ])
408409 results .extend (r )
409410 return results
410411
411412 # give up and return first track
412413 for track in item .tracks :
413414 r = _walk_reference_chain (track .component , time , [])
414415 if r :
415- results .append ([time , track ])
416+ results .append ([RationalTime ( time , item . edit_rate ) , track ])
416417 results .extend (r )
417418 return r
418419
@@ -428,7 +429,16 @@ def _walk_reference_chain(item, time, results):
428429
429430def _extract_timecode_info (source_mob , start_time ):
430431
432+ # Please note, timecode and frame rate are not the same thing!
433+ # Timecode is a way to label frames in a recording and
434+ # frame rate is the speed at which images have been
435+ # recorded or are played back. Timecode should NOT be treated as
436+ # a unit of time but rather a frame index. Fortunately AVB stores
437+ # timecode as a frame offset.
438+
431439 # TODO: need to find sample with multiple timecode samples
440+
441+ assert isinstance (start_time , RationalTime )
432442 for track in source_mob .tracks :
433443 if track .component .media_kind == 'timecode' :
434444
@@ -441,22 +451,27 @@ def _extract_timecode_info(source_mob, start_time):
441451
442452 # start timecode is the first timecode sample
443453 timecode , _ = component .nearest_component_at_time (0 )
444- track_tc = timecode .start
454+ track_tc = RationalTime ( timecode .start , timecode . edit_rate )
445455
446456 # source timecode is nearest timecode sample
447- tc , tc_offset = component .nearest_component_at_time (start_time )
448- source_tc = tc .start + start_time - tc_offset
457+ scale_time = start_time .value_rescaled_to (component .edit_rate )
458+ tc , tc_offset = component .nearest_component_at_time (scale_time )
459+
460+ tc_offset = RationalTime (tc_offset , tc .edit_rate )
461+ tc_start = RationalTime (tc .start , tc .edit_rate )
449462
450- return track_tc , source_tc , timecode .fps
463+ source_tc = tc_start + start_time - tc_offset
464+
465+ return track_tc , source_tc
451466
452467 elif isinstance (track .component , avb .components .Timecode ):
453468 timecode = track .component
454- track_tc = timecode .start
469+ track_tc = RationalTime ( timecode .start , timecode . edit_rate )
455470 source_tc = track_tc + start_time
456471
457- return track_tc , source_tc , timecode . fps
472+ return track_tc , source_tc
458473
459- return None , None , None
474+ return None , None
460475
461476
462477def _add_child (parent , child , source ):
@@ -579,12 +594,11 @@ def _transcribe(item, parents, edit_rate, indent=0):
579594 mobs = [mob for start , mob in ref_chain
580595 if isinstance (mob , avb .trackgroups .Composition )]
581596
582- source_start = item .start_time
583- source_length = item .length
597+ source_start = RationalTime ( item .start_time , item . edit_rate )
598+ source_length = RationalTime ( item .length , item . edit_rate )
584599
585- media_start = 0
586- media_length = item .length
587- media_edit_rate = edit_rate
600+ media_start = RationalTime (0 , item .edit_rate )
601+ media_length = source_length
588602
589603 source_mob = None
590604 for start_time , comp in ref_chain :
@@ -594,24 +608,19 @@ def _transcribe(item, parents, edit_rate, indent=0):
594608
595609 if isinstance (comp , avb .components .SourceClip ):
596610 source_start = start_time
597- media_start = comp .start_time
598- media_length = comp .length
599- media_edit_rate = comp .edit_rate
611+ media_start = RationalTime (comp .start_time , comp .edit_rate )
612+ media_length = RationalTime (comp .length , comp .edit_rate )
600613
601614 if source_mob :
602- track_tc , source_tc , tc_rate = _extract_timecode_info (source_mob ,
603- start_time )
604- if track_tc is not None :
605- source_start = source_tc
606- media_start = track_tc
607- media_edit_rate = tc_rate
608-
609- # NOTE: duration is in the edit rate of the source clip
610- # and start_time is in edit rate of the source media
611- # need to further test this
615+ track_tc_start , source_tc_start = _extract_timecode_info (source_mob ,
616+ start_time )
617+ if track_tc_start is not None :
618+ source_start = source_tc_start
619+ media_start = track_tc_start
620+
612621 result .source_range = otio .opentime .TimeRange (
613- otio . opentime . RationalTime ( source_start , media_edit_rate ) ,
614- otio . opentime . RationalTime ( source_length , edit_rate )
622+ source_start ,
623+ source_length ,
615624 )
616625
617626 mastermobs = []
@@ -676,8 +685,8 @@ def _transcribe(item, parents, edit_rate, indent=0):
676685 media = otio .schema .MissingReference ()
677686
678687 media .available_range = otio .opentime .TimeRange (
679- otio . opentime . RationalTime ( media_start , media_edit_rate ) ,
680- otio . opentime . RationalTime ( media_length , media_edit_rate )
688+ media_start ,
689+ media_length ,
681690 )
682691
683692 # Copy the metadata from the master into the media_reference
@@ -890,17 +899,12 @@ def _find_timecode_track_start(track):
890899 if not isinstance (track .component , avb .components .Timecode ):
891900 return
892901
893- edit_rate = fractions . Fraction ( track .component .fps )
902+ edit_rate = track .component .edit_rate
894903 start = track .component .start
895904
896- if edit_rate .denominator == 1 :
897- rate = edit_rate .numerator
898- else :
899- rate = float (edit_rate )
900-
901905 return otio .opentime .RationalTime (
902- value = int ( start ) ,
903- rate = rate ,
906+ value = start ,
907+ rate = edit_rate ,
904908 )
905909
906910
0 commit comments