Skip to content

Commit 554004e

Browse files
committed
Added getMetadataJSON() and setMetadataJSON()
Signed-off-by: Joshua Minor <joshm@pixar.com>
1 parent f357b4d commit 554004e

5 files changed

Lines changed: 162 additions & 32 deletions

File tree

Sources/objc/include/opentimelineio.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#import "CxxAnyVectorMutationStamp.h"
1212
#import "CxxVectorProperty.h"
1313
#import "errorStruct.h"
14+
#import "CxxAny.h"
1415

1516
#if defined(__cplusplus)
1617
extern "C" {
@@ -81,10 +82,14 @@ NSString* unknown_schema_original_schema_name(CxxRetainer* self);
8182
int unknown_schema_original_schema_version(CxxRetainer* self);
8283

8384
// MARK: - SerializableObjectWithMetadata
84-
85+
8586
NSString* serializable_object_with_metadata_name(CxxRetainer* self);
8687
void serializable_object_with_metadata_set_name(CxxRetainer* self, NSString* name);
8788
void* serializable_object_with_metadata_metadata(CxxRetainer* self);
89+
90+
// MARK: - AnyValue JSON
91+
NSString* _Nullable any_value_to_json_string(CxxAny* _Nonnull value, int indent, CxxErrorStruct* _Nonnull err);
92+
bool any_value_from_json_string(NSString* _Nonnull input, CxxAny* _Nonnull result, CxxErrorStruct* _Nonnull err);
8893

8994
// MARK: - Clip
9095
void* _Nullable clip_media_reference(CxxRetainer* self);

Sources/objc/opentimelineio.mm

Lines changed: 72 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
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>
@@ -22,17 +23,19 @@
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"
@@ -97,11 +100,11 @@
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

199201
NSString* 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+
220222
bool 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
280327
void* 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) {
479526
CxxVectorProperty* 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
646693
bool 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

661708
void 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+
722769
NSArray* 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) {
769816
NSString* external_reference_get_target_url(CxxRetainer* self) {
770817
return make_nsstring(SO_cast<otio::ExternalReference>(self)->target_url());
771818
}
772-
819+
773820
void 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)
782829
void generator_reference_set_generator_kind(CxxRetainer* self, NSString* kind) {
783830
SO_cast<otio::GeneratorReference>(self)->set_generator_kind([kind UTF8String]);
784831
}
785-
832+
786833
void* 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) {
791838
double linear_time_warp_get_time_scalar(CxxRetainer* self) {
792839
return SO_cast<otio::LinearTimeWarp>(self)->time_scalar();
793840
}
794-
841+
795842
void 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

807854
void* 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

812859
void* algorithms_flatten_track_array(NSArray* tracks, CxxErrorStruct* cxxErr) {

Sources/swift/Metadata.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ public enum Metadata {
417417
return CxxAny(type_code: Int32(type.rawValue), value: value)
418418
}
419419

420-
private static func withCxxAny(_ value: MetadataValue, work: (CxxAny) -> ()) {
420+
static func withCxxAny(_ value: MetadataValue, work: (CxxAny) -> ()) {
421421
switch value.metadataType {
422422
case .none:
423423
work(createCxxAny(.none, .init(i: 0)))

Sources/swift/SerializableObjectWithMetadata.swift

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,46 @@ public class SerializableObjectWithMetadata : SerializableObject {
3535
}
3636
}
3737
}
38-
38+
3939
override public var description: String {
4040
let addr = ObjectIdentifier(self).hashValue
4141
let addr2 = Int(bitPattern: cxxSerializableObject())
4242
return "\(String(describing: type(of: self))) named '\(name)' <swift: 0x\(String(format: "%x", addr)), C++: \(String(format: "%p", addr2))>"
4343
}
44-
44+
4545
public var name: String {
4646
get { return serializable_object_with_metadata_name(self) }
4747
set { serializable_object_with_metadata_set_name(self, newValue) }
4848
}
49-
49+
5050
public var metadata: Metadata.Dictionary {
5151
get { return Metadata.Dictionary.wrap(anyDictionaryPtr: serializable_object_with_metadata_metadata(self), cxxRetainer: self) }
5252
}
53-
53+
54+
public func getMetadataJSON(_ key: String) throws -> String? {
55+
guard let value: MetadataValue = metadata[key] else {
56+
return nil
57+
}
58+
var jsonString: String? = nil
59+
var thrownError: Error? = nil
60+
Metadata.withCxxAny(value) { cxxAny in
61+
var mutableCxxAny = cxxAny
62+
do {
63+
jsonString = try OTIOError.returnOrThrow { any_value_to_json_string(&mutableCxxAny, 4, &$0) }
64+
} catch {
65+
thrownError = error
66+
}
67+
}
68+
if let error = thrownError { throw error }
69+
return jsonString
70+
}
71+
72+
public func setMetadataJSON(_ key: String, _ value: String) throws {
73+
var cxxAny = CxxAny()
74+
_ = try OTIOError.returnOrThrow { any_value_from_json_string(value, &cxxAny, &$0) }
75+
metadata[key] = Metadata.cxxAnyToMetadataValue(cxxAny)
76+
}
77+
5478
override internal init(_ cxxPtr: CxxSerializableObjectPtr) {
5579
super.init(cxxPtr)
5680
}

0 commit comments

Comments
 (0)