diff --git a/src/py-opentimelineio/opentimelineio/adapters/cmx_3600.py b/src/py-opentimelineio/opentimelineio/adapters/cmx_3600.py index bd1696260..a4625ac47 100644 --- a/src/py-opentimelineio/opentimelineio/adapters/cmx_3600.py +++ b/src/py-opentimelineio/opentimelineio/adapters/cmx_3600.py @@ -627,6 +627,16 @@ def parse(self, comment): self.unhandled.append(stripped) +def _get_next_clip(start_index, track): + """Get the next clip with a non-zero duration""" + # Iterate over the following clips and return the first "real" one + for clip in track[start_index + 1:]: + if clip.duration().value > 0: + return clip + + return None + + def _expand_transitions(timeline): """Convert clips with metadata/transition == 'D' into OTIO transitions.""" @@ -635,13 +645,10 @@ def _expand_transitions(timeline): replace_or_insert_list = [] append_list = [] for track in tracks: - track_iter = iter(track) # avid inserts an extra clip for the source prev_prev = None prev = None - clip = next(track_iter, None) - next_clip = next(track_iter, None) - while clip is not None: + for index, clip in enumerate(track): transition_type = clip.metadata.get('cmx_3600', {}).get( 'transition', 'C' @@ -651,8 +658,6 @@ def _expand_transitions(timeline): # nothing to do, continue to the next iteration of the loop prev_prev = prev prev = clip - clip = next_clip - next_clip = next(track_iter, None) continue wipe_match = re.match(r'W(\d{3})', transition_type) @@ -730,6 +735,7 @@ def _expand_transitions(timeline): # expand the next_clip or contract this clip keep_transition_clip = False + next_clip = _get_next_clip(index, track) if next_clip: if _transition_clips_continuous(clip, next_clip): sr = next_clip.source_range @@ -771,8 +777,6 @@ def _expand_transitions(timeline): del(new_trx.metadata['previous_metadata']) prev = clip - clip = next_clip - next_clip = next(track_iter, None) for (insert, track, from_clip, to_transition) in replace_or_insert_list: clip_index = track.index(from_clip) diff --git a/tests/sample_data/dissolve_test_4.edl b/tests/sample_data/dissolve_test_4.edl new file mode 100644 index 000000000..7d59ceb1c --- /dev/null +++ b/tests/sample_data/dissolve_test_4.edl @@ -0,0 +1,12 @@ +TITLE: TRANSITION_TEST_2 +FCM: NON-DROP FRAME +001 ABC0000. V C 01:00:06:18 01:00:08:00 01:04:11:17 01:04:12:23 +002 ABC0010. V C 01:00:06:15 01:00:08:18 01:04:12:23 01:04:15:02 +003 ABC0010. V C 01:00:08:18 01:00:08:18 01:04:15:02 01:04:15:02 +003 ABC0020. V D 035 01:00:06:22 01:00:10:07 01:04:15:02 01:04:18:11 +* BLEND, DISSOLVE +004 ABC0020. V C 01:00:10:07 01:00:10:07 01:04:18:11 01:04:18:11 +004 ABC0030. V D 064 01:00:06:10 01:00:09:22 01:04:18:11 01:04:21:23 +* BLEND, DISSOLVE +005 ABC0040. V C 01:00:08:14 01:00:12:14 01:04:21:23 01:04:25:23 +060 ABC0050. V C 01:00:12:06 01:00:17:21 01:04:25:23 01:04:31:14 diff --git a/tests/test_cmx_3600_adapter.py b/tests/test_cmx_3600_adapter.py index c7843afea..34d8a3c0f 100755 --- a/tests/test_cmx_3600_adapter.py +++ b/tests/test_cmx_3600_adapter.py @@ -50,6 +50,7 @@ DISSOLVE_TEST = os.path.join(SAMPLE_DATA_DIR, "dissolve_test.edl") DISSOLVE_TEST_2 = os.path.join(SAMPLE_DATA_DIR, "dissolve_test_2.edl") DISSOLVE_TEST_3 = os.path.join(SAMPLE_DATA_DIR, "dissolve_test_3.edl") +DISSOLVE_TEST_4 = os.path.join(SAMPLE_DATA_DIR, "dissolve_test_4.edl") GAP_TEST = os.path.join(SAMPLE_DATA_DIR, "gap_test.edl") WIPE_TEST = os.path.join(SAMPLE_DATA_DIR, "wipe_test.edl") TIMECODE_MISMATCH_TEST = os.path.join(SAMPLE_DATA_DIR, "timecode_mismatch.edl") @@ -1047,6 +1048,26 @@ def test_transition_duration(self): self.assertEqual(tl.tracks[0][2].duration().value, 26.0) + def test_three_part_transition(self): + """ + Test A->B->C Transition + """ + tl = otio.adapters.read_from_file(DISSOLVE_TEST_4) + self.assertEqual(len(tl.tracks[0]), 8) + + self.assertIsInstance(tl.tracks[0][2], otio.schema.Transition) + self.assertIsInstance(tl.tracks[0][4], otio.schema.Transition) + + self.assertEqual(tl.tracks[0][2].duration().value, 35.0) + self.assertEqual(tl.tracks[0][4].duration().value, 64.0) + + self.assertEqual(tl.tracks[0][0].duration().value, 30.0) + self.assertEqual(tl.tracks[0][1].duration().value, 68.0) + self.assertEqual(tl.tracks[0][3].duration().value, 96.0) + self.assertEqual(tl.tracks[0][5].duration().value, 52.0) + self.assertEqual(tl.tracks[0][6].duration().value, 96.0) + self.assertEqual(tl.tracks[0][7].duration().value, 135.0) + if __name__ == "__main__": unittest.main()