@@ -338,5 +338,94 @@ def test_use_in_available_streams(self):
338338 self .assertIn (StreamInfo .Identifier .stereo_left , streams )
339339
340340
341+ class TestStreamMapper (unittest .TestCase ):
342+ def test_create_default (self ):
343+ mapper = otio .schema .StreamMapper ()
344+ self .assertEqual (mapper .stream_map , {})
345+ self .assertEqual (mapper .schema_name (), "StreamMapper" )
346+ self .assertEqual (mapper .schema_version (), 1 )
347+
348+ def test_create_with_map (self ):
349+ stream_map = {
350+ StreamInfo .Identifier .monocular : StreamInfo .Identifier .left_eye
351+ }
352+ mapper = otio .schema .StreamMapper (stream_map = stream_map )
353+ self .assertEqual (mapper .stream_map , stream_map )
354+
355+ def test_set_map (self ):
356+ mapper = otio .schema .StreamMapper ()
357+ stream_map = {
358+ StreamInfo .Identifier .stereo_left : StreamInfo .Identifier .surround_left_front ,
359+ StreamInfo .Identifier .stereo_right : StreamInfo .Identifier .surround_right_front ,
360+ }
361+ mapper .stream_map = stream_map
362+ self .assertEqual (mapper .stream_map , stream_map )
363+
364+ def test_round_trip_serialization (self ):
365+ stream_map = {
366+ StreamInfo .Identifier .monocular : StreamInfo .Identifier .left_eye
367+ }
368+ mapper = otio .schema .StreamMapper (
369+ name = "remap_to_mono" ,
370+ stream_map = stream_map ,
371+ )
372+ json_str = mapper .to_json_string ()
373+ restored = otio .adapters .read_from_string (json_str , "otio_json" )
374+ self .assertIsInstance (restored , otio .schema .StreamMapper )
375+ self .assertEqual (restored .name , "remap_to_mono" )
376+ self .assertEqual (restored .stream_map , stream_map )
377+
378+ def test_left_eye_to_monocular_use_case (self ):
379+ """StreamMapper can remap left_eye to monocular for downstream consumers."""
380+ clip = otio .schema .Clip (
381+ name = "stereo_shot" ,
382+ media_reference = otio .schema .ExternalReference (
383+ target_url = "/path/to/stereo.mov"
384+ ),
385+ effects = [
386+ otio .schema .StreamMapper (
387+ stream_map = {
388+ StreamInfo .Identifier .monocular : StreamInfo .Identifier .left_eye
389+ }
390+ )
391+ ]
392+ )
393+ mapper = clip .effects [0 ]
394+ self .assertIsInstance (mapper , otio .schema .StreamMapper )
395+ self .assertEqual (
396+ mapper .stream_map [StreamInfo .Identifier .monocular ],
397+ StreamInfo .Identifier .left_eye
398+ )
399+
400+ def test_use_as_clip_effect (self ):
401+ """StreamMapper round-trips correctly when embedded in a clip."""
402+ clip = otio .schema .Clip (
403+ name = "remapped_clip" ,
404+ media_reference = otio .schema .ExternalReference (
405+ target_url = "/path/to/source.mov"
406+ ),
407+ effects = [
408+ otio .schema .StreamMapper (
409+ name = "a very bad stereo downmix" ,
410+ stream_map = {
411+ StreamInfo .Identifier .stereo_left : StreamInfo .Identifier .surround_left_front ,
412+ StreamInfo .Identifier .stereo_right : StreamInfo .Identifier .surround_right_front ,
413+ }
414+ )
415+ ]
416+ )
417+ json_str = clip .to_json_string ()
418+ restored = otio .adapters .read_from_string (json_str , "otio_json" )
419+ self .assertIsInstance (restored , otio .schema .Clip )
420+ self .assertEqual (len (restored .effects ), 1 )
421+ mapper = restored .effects [0 ]
422+ self .assertIsInstance (mapper , otio .schema .StreamMapper )
423+ self .assertEqual (mapper .name , "A very bad stereo downmix" )
424+ self .assertEqual (
425+ mapper .stream_map [StreamInfo .Identifier .stereo_left ],
426+ StreamInfo .Identifier .surround_left_front
427+ )
428+
429+
341430if __name__ == "__main__" :
342431 unittest .main ()
0 commit comments