99#include < opentimelineio/clip.h>
1010#include < opentimelineio/composable.h>
1111#include < opentimelineio/composition.h>
12+ #include < opentimelineio/deserialization.h>
1213#include < opentimelineio/effect.h>
1314#include < opentimelineio/externalReference.h>
1415#include < opentimelineio/freezeFrame.h>
2223#include < opentimelineio/serializableCollection.h>
2324#include < opentimelineio/serializableObject.h>
2425#include < opentimelineio/serializableObjectWithMetadata.h>
26+ #include < opentimelineio/serialization.h>
2527#include < opentimelineio/stack.h>
28+ #include < opentimelineio/stack.h>
29+ #include < opentimelineio/stackAlgorithm.h>
30+ #include < opentimelineio/stringUtils.h>
31+ #include < opentimelineio/stringUtils.h>
2632#include < opentimelineio/timeEffect.h>
2733#include < opentimelineio/timeline.h>
2834#include < opentimelineio/track.h>
35+ #include < opentimelineio/trackAlgorithm.h>
2936#include < opentimelineio/transition.h>
30- #include < opentimelineio/stack.h>
31- #include < opentimelineio/stringUtils.h>
3237#include < opentimelineio/unknownSchema.h>
33- #include < opentimelineio/stringUtils.h>
34- #include < opentimelineio/trackAlgorithm.h>
35- #include < opentimelineio/stackAlgorithm.h>
38+
3639
3740#import " opentimelineio.h"
3841#import " opentime.h"
97100 otio::AnyDictionary d, d2;
98101 d["abc"] = 123;
99102 d["xyz"] = 456;
100-
103+
101104 d2["r1"] = otio::RationalTime(1,2);
102105 d2["r2"] = otio::RationalTime(100,200);
103106 d2["plugh"] = 37;
104-
107+
105108 d["nested"] = d2;
106109 c->metadata() = d;
107110 return c;*/
@@ -193,7 +196,6 @@ void serializable_object_to_json_file(CxxRetainer* self, NSString* filename, sch
193196 _AutoErrorHandler aeh (cxxErr);
194197 otio::schema_version_map map = _to_cxx_schema_version_map (target_family_label_spec);
195198 self.retainer .value ->to_json_file (filename.UTF8String , &aeh.error_status , &map, indent);
196-
197199}
198200
199201NSString * serializable_object_to_json_string (CxxRetainer* self, schema_version_map *target_family_label_spec, int indent, CxxErrorStruct* cxxErr) {
@@ -216,7 +218,7 @@ void serializable_object_to_json_file(CxxRetainer* self, NSString* filename, sch
216218 _AutoErrorHandler aeh (cxxErr);
217219 return self.retainer .value ->clone (&aeh.error_status );
218220}
219-
221+
220222bool serializable_object_is_equivalent_to (CxxRetainer* lhs, CxxRetainer* rhs) {
221223 return lhs.retainer .value ->is_equivalent_to (*rhs.retainer .value );
222224}
@@ -276,6 +278,51 @@ void serializable_object_with_metadata_set_name(CxxRetainer* self, NSString* nam
276278 return &SO_cast<otio::SerializableObjectWithMetadata>(self)->metadata ();
277279}
278280
281+ // MARK: - AnyValue JSON
282+
283+ NSString * any_value_to_json_string (CxxAny* value, int indent, CxxErrorStruct* cxxErr) {
284+ _AutoErrorHandler aeh (cxxErr);
285+ std::any otioAny = cxx_any_to_otio_any (*value);
286+ std::string result = otio::serialize_json_to_string (otioAny, nullptr , &aeh.error_status , indent);
287+ if (aeh.error_status .outcome != otio::ErrorStatus::OK) {
288+ return nil ;
289+ }
290+ return make_nsstring (result);
291+ }
292+
293+ bool any_value_from_json_string (NSString * input, CxxAny* result, CxxErrorStruct* cxxErr) {
294+ // Thread-local buffers keep heap-pointer values alive after otioAny goes out of scope.
295+ static thread_local std::string s_string_value;
296+ static thread_local otio::AnyDictionary s_dict_value;
297+ static thread_local otio::AnyVector s_vector_value;
298+
299+ _AutoErrorHandler aeh (cxxErr);
300+ std::any otioAny;
301+ bool ok = otio::deserialize_json_from_string (input.UTF8String , &otioAny, &aeh.error_status );
302+ if (!ok) {
303+ return false ;
304+ }
305+ otio_any_to_cxx_any (otioAny, result);
306+ // Fix up pointer-typed results whose pointers would dangle once otioAny is destroyed.
307+ switch (result->type_code ) {
308+ case CxxAny::STRING:
309+ s_string_value = std::any_cast<std::string const &>(otioAny);
310+ result->value .s = s_string_value.c_str ();
311+ break ;
312+ case CxxAny::DICTIONARY:
313+ s_dict_value = std::any_cast<otio::AnyDictionary const &>(otioAny);
314+ result->value .ptr = &s_dict_value;
315+ break ;
316+ case CxxAny::VECTOR:
317+ s_vector_value = std::any_cast<otio::AnyVector const &>(otioAny);
318+ result->value .ptr = &s_vector_value;
319+ break ;
320+ default :
321+ break ;
322+ }
323+ return true ;
324+ }
325+
279326// MARK: - Composable
280327void * composable_parent (CxxRetainer* self) {
281328 return SO_cast<otio::Composable>(self)->parent ();
@@ -382,7 +429,7 @@ bool item_trimmed_range_in_parent(CxxRetainer* self, CxxTimeRange* tr, CxxErrorS
382429 _AutoErrorHandler aeh (cxxErr);
383430 auto item = SO_cast<otio::Item>(self);
384431 auto result = item->trimmed_range_in_parent (&aeh.error_status );
385-
432+
386433 if (result) {
387434 *tr = cxxTimeRange (*result);
388435 return true ;
@@ -479,7 +526,7 @@ void clip_set_media_reference(CxxRetainer* self, CxxRetainer* media_reference) {
479526CxxVectorProperty* create_composition_children_vector_property (CxxRetainer* self) {
480527 auto composition = SO_cast<otio::Composition>(self);
481528 auto p = [CxxVectorProperty new ];
482-
529+
483530 // Yes, I know: but we're not going to mutate this and neither is anybody else.
484531 // We're only going to look at it.
485532 auto & children = const_cast <std::vector<otio::SerializableObject::Retainer<otio::Composable>>&>(composition->children ());
@@ -521,13 +568,13 @@ void composition_append_child(CxxRetainer* self, CxxRetainer* child_retainer, Cx
521568 auto dict = [NSMutableDictionary new ];
522569 _AutoErrorHandler aeh (cxxErr);
523570 auto result = SO_cast<otio::Composition>(self)->range_of_all_children (&aeh.error_status );
524-
571+
525572 for (auto item: result) {
526573 auto tr = cxxTimeRange (item.second );
527574 [dict setObject: [NSValue valueWithBytes: &tr objCType: @encode (CxxTimeRange)]
528575 forKey: [NSValue valueWithPointer: item.first]];
529576 }
530-
577+
531578 return dict;
532579}
533580
@@ -548,15 +595,15 @@ void composition_handles_of_child(CxxRetainer* self, CxxRetainer* composable,
548595 bool * hasLeft, bool * hasRight, CxxErrorStruct* cxxErr) {
549596 _AutoErrorHandler aeh (cxxErr);
550597 auto result = SO_cast<otio::Composition>(self)->handles_of_child (SO_cast<otio::Composable>(composable), &aeh.error_status );
551-
598+
552599 if (result.first ) {
553600 *hasLeft = true ;
554601 *rt1 = cxxRationalTime (*(result.first ));
555602 }
556603 else {
557604 *hasLeft = false ;
558605 }
559-
606+
560607 if (result.second ) {
561608 *hasRight = true ;
562609 *rt2 = cxxRationalTime (*(result.second ));
@@ -645,27 +692,27 @@ void media_reference_clear_available_range(CxxRetainer* self) {
645692// If true, value of passed in rect is set. If false, there was no media reference bounds
646693bool media_reference_available_image_bounds (CxxRetainer* self, CGRect* rect) {
647694 std::optional<IMATH_NAMESPACE::Box2d> iBox2D = SO_cast<otio::MediaReference>(self)->available_image_bounds ();
648-
695+
649696 if (iBox2D) {
650697 rect->origin .x = iBox2D->min .x ;
651698 rect->origin .y = iBox2D->min .y ;
652699 rect->size .width = iBox2D->max .x - iBox2D->min .x ;
653700 rect->size .height = iBox2D->max .y - iBox2D->min .y ;
654-
701+
655702 return true ;
656703 }
657-
704+
658705 return false ;
659706}
660707
661708void media_reference_set_available_image_bounds (CxxRetainer* self, CGRect image_bounds) {
662709 std::optional<IMATH_NAMESPACE::Box2d> iBox2D = std::optional<IMATH_NAMESPACE::Box2d>();
663-
710+
664711 iBox2D->min .x = image_bounds.origin .x ;
665712 iBox2D->min .y = image_bounds.origin .y ;
666713 iBox2D->max .x = image_bounds.size .width + image_bounds.origin .x ;
667714 iBox2D->max .y = image_bounds.size .height + image_bounds.origin .y ;
668-
715+
669716 SO_cast<otio::MediaReference>(self)->set_available_image_bounds (iBox2D);
670717}
671718
@@ -718,7 +765,7 @@ CxxTimeRange timeline_range_of_child(CxxRetainer* self, CxxRetainer* child, CxxE
718765 }
719766 return array;
720767}
721-
768+
722769NSArray * timeline_video_tracks (CxxRetainer* self) {
723770 auto array = [NSMutableArray new ];
724771 for (auto t: SO_cast<otio::Timeline>(self)->video_tracks ()) {
@@ -769,7 +816,7 @@ void effect_set_name(CxxRetainer* self, NSString* name) {
769816NSString * external_reference_get_target_url (CxxRetainer* self) {
770817 return make_nsstring (SO_cast<otio::ExternalReference>(self)->target_url ());
771818}
772-
819+
773820void external_reference_set_target_url (CxxRetainer* self, NSString * target_url) {
774821 SO_cast<otio::ExternalReference>(self)->set_target_url ([target_url UTF8String ]);
775822}
@@ -782,7 +829,7 @@ void external_reference_set_target_url(CxxRetainer* self, NSString* target_url)
782829void generator_reference_set_generator_kind (CxxRetainer* self, NSString * kind) {
783830 SO_cast<otio::GeneratorReference>(self)->set_generator_kind ([kind UTF8String ]);
784831}
785-
832+
786833void * generator_reference_parameters (CxxRetainer* self) {
787834 return &SO_cast<otio::GeneratorReference>(self)->parameters ();
788835}
@@ -791,7 +838,7 @@ void generator_reference_set_generator_kind(CxxRetainer* self, NSString* kind) {
791838double linear_time_warp_get_time_scalar (CxxRetainer* self) {
792839 return SO_cast<otio::LinearTimeWarp>(self)->time_scalar ();
793840}
794-
841+
795842void linear_time_warp_set_time_scalar (CxxRetainer* self, double time_scalar) {
796843 SO_cast<otio::LinearTimeWarp>(self)->set_time_scalar (time_scalar);
797844}
@@ -806,7 +853,7 @@ void linear_time_warp_set_time_scalar(CxxRetainer* self, double time_scalar) {
806853
807854void * algorithms_flatten_stack (CxxRetainer* in_stack, CxxErrorStruct* cxxErr) {
808855 _AutoErrorHandler aeh (cxxErr);
809- return otio::flatten_stack (SO_cast<otio::Stack>(in_stack), &aeh.error_status );
856+ return otio::flatten_stack (SO_cast<otio::Stack>(in_stack), &aeh.error_status );
810857}
811858
812859void * algorithms_flatten_track_array (NSArray * tracks, CxxErrorStruct* cxxErr) {
0 commit comments