Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Sources/objc/include/opentimelineio.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#import "CxxAnyVectorMutationStamp.h"
#import "CxxVectorProperty.h"
#import "errorStruct.h"
#import "CxxAny.h"

#if defined(__cplusplus)
extern "C" {
Expand Down Expand Up @@ -81,10 +82,14 @@ NSString* unknown_schema_original_schema_name(CxxRetainer* self);
int unknown_schema_original_schema_version(CxxRetainer* self);

// MARK: - SerializableObjectWithMetadata

NSString* serializable_object_with_metadata_name(CxxRetainer* self);
void serializable_object_with_metadata_set_name(CxxRetainer* self, NSString* name);
void* serializable_object_with_metadata_metadata(CxxRetainer* self);

// MARK: - AnyValue JSON
NSString* _Nullable any_value_to_json_string(CxxAny* _Nonnull value, int indent, CxxErrorStruct* _Nonnull err);
bool any_value_from_json_string(NSString* _Nonnull input, CxxAny* _Nonnull result, CxxErrorStruct* _Nonnull err);

// MARK: - Clip
void* _Nullable clip_media_reference(CxxRetainer* self);
Expand Down
97 changes: 72 additions & 25 deletions Sources/objc/opentimelineio.mm
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <opentimelineio/clip.h>
#include <opentimelineio/composable.h>
#include <opentimelineio/composition.h>
#include <opentimelineio/deserialization.h>
#include <opentimelineio/effect.h>
#include <opentimelineio/externalReference.h>
#include <opentimelineio/freezeFrame.h>
Expand All @@ -22,17 +23,19 @@
#include <opentimelineio/serializableCollection.h>
#include <opentimelineio/serializableObject.h>
#include <opentimelineio/serializableObjectWithMetadata.h>
#include <opentimelineio/serialization.h>
#include <opentimelineio/stack.h>
#include <opentimelineio/stack.h>
#include <opentimelineio/stackAlgorithm.h>
#include <opentimelineio/stringUtils.h>
#include <opentimelineio/stringUtils.h>
#include <opentimelineio/timeEffect.h>
#include <opentimelineio/timeline.h>
#include <opentimelineio/track.h>
#include <opentimelineio/trackAlgorithm.h>
#include <opentimelineio/transition.h>
#include <opentimelineio/stack.h>
#include <opentimelineio/stringUtils.h>
#include <opentimelineio/unknownSchema.h>
#include <opentimelineio/stringUtils.h>
#include <opentimelineio/trackAlgorithm.h>
#include <opentimelineio/stackAlgorithm.h>


#import "opentimelineio.h"
#import "opentime.h"
Expand Down Expand Up @@ -97,11 +100,11 @@
otio::AnyDictionary d, d2;
d["abc"] = 123;
d["xyz"] = 456;

d2["r1"] = otio::RationalTime(1,2);
d2["r2"] = otio::RationalTime(100,200);
d2["plugh"] = 37;

d["nested"] = d2;
c->metadata() = d;
return c;*/
Expand Down Expand Up @@ -193,7 +196,6 @@ void serializable_object_to_json_file(CxxRetainer* self, NSString* filename, sch
_AutoErrorHandler aeh(cxxErr);
otio::schema_version_map map = _to_cxx_schema_version_map(target_family_label_spec);
self.retainer.value->to_json_file(filename.UTF8String, &aeh.error_status, &map, indent);

}

NSString* serializable_object_to_json_string(CxxRetainer* self, schema_version_map *target_family_label_spec, int indent, CxxErrorStruct* cxxErr) {
Expand All @@ -216,7 +218,7 @@ void serializable_object_to_json_file(CxxRetainer* self, NSString* filename, sch
_AutoErrorHandler aeh(cxxErr);
return self.retainer.value->clone(&aeh.error_status);
}

bool serializable_object_is_equivalent_to(CxxRetainer* lhs, CxxRetainer* rhs) {
return lhs.retainer.value->is_equivalent_to(*rhs.retainer.value);
}
Expand Down Expand Up @@ -276,6 +278,51 @@ void serializable_object_with_metadata_set_name(CxxRetainer* self, NSString* nam
return &SO_cast<otio::SerializableObjectWithMetadata>(self)->metadata();
}

// MARK: - AnyValue JSON

NSString* any_value_to_json_string(CxxAny* value, int indent, CxxErrorStruct* cxxErr) {
_AutoErrorHandler aeh(cxxErr);
std::any otioAny = cxx_any_to_otio_any(*value);
std::string result = otio::serialize_json_to_string(otioAny, nullptr, &aeh.error_status, indent);
if (aeh.error_status.outcome != otio::ErrorStatus::OK) {
return nil;
}
return make_nsstring(result);
}

bool any_value_from_json_string(NSString* input, CxxAny* result, CxxErrorStruct* cxxErr) {
// Thread-local buffers keep heap-pointer values alive after otioAny goes out of scope.
static thread_local std::string s_string_value;
static thread_local otio::AnyDictionary s_dict_value;
static thread_local otio::AnyVector s_vector_value;

_AutoErrorHandler aeh(cxxErr);
std::any otioAny;
bool ok = otio::deserialize_json_from_string(input.UTF8String, &otioAny, &aeh.error_status);
if (!ok) {
return false;
}
otio_any_to_cxx_any(otioAny, result);
// Fix up pointer-typed results whose pointers would dangle once otioAny is destroyed.
switch (result->type_code) {
case CxxAny::STRING:
s_string_value = std::any_cast<std::string const&>(otioAny);
result->value.s = s_string_value.c_str();
break;
case CxxAny::DICTIONARY:
s_dict_value = std::any_cast<otio::AnyDictionary const&>(otioAny);
result->value.ptr = &s_dict_value;
break;
case CxxAny::VECTOR:
s_vector_value = std::any_cast<otio::AnyVector const&>(otioAny);
result->value.ptr = &s_vector_value;
break;
default:
break;
}
return true;
}

// MARK: - Composable
void* composable_parent(CxxRetainer* self) {
return SO_cast<otio::Composable>(self)->parent();
Expand Down Expand Up @@ -382,7 +429,7 @@ bool item_trimmed_range_in_parent(CxxRetainer* self, CxxTimeRange* tr, CxxErrorS
_AutoErrorHandler aeh(cxxErr);
auto item = SO_cast<otio::Item>(self);
auto result = item->trimmed_range_in_parent(&aeh.error_status);

if (result) {
*tr = cxxTimeRange(*result);
return true;
Expand Down Expand Up @@ -479,7 +526,7 @@ void clip_set_media_reference(CxxRetainer* self, CxxRetainer* media_reference) {
CxxVectorProperty* create_composition_children_vector_property(CxxRetainer* self) {
auto composition = SO_cast<otio::Composition>(self);
auto p = [CxxVectorProperty new];

// Yes, I know: but we're not going to mutate this and neither is anybody else.
// We're only going to look at it.
auto& children = const_cast<std::vector<otio::SerializableObject::Retainer<otio::Composable>>&>(composition->children());
Expand Down Expand Up @@ -521,13 +568,13 @@ void composition_append_child(CxxRetainer* self, CxxRetainer* child_retainer, Cx
auto dict = [NSMutableDictionary new];
_AutoErrorHandler aeh(cxxErr);
auto result = SO_cast<otio::Composition>(self)->range_of_all_children(&aeh.error_status);

for (auto item: result) {
auto tr = cxxTimeRange(item.second);
[dict setObject: [NSValue valueWithBytes:&tr objCType:@encode(CxxTimeRange)]
forKey: [NSValue valueWithPointer:item.first]];
}

return dict;
}

Expand All @@ -548,15 +595,15 @@ void composition_handles_of_child(CxxRetainer* self, CxxRetainer* composable,
bool* hasLeft, bool* hasRight, CxxErrorStruct* cxxErr) {
_AutoErrorHandler aeh(cxxErr);
auto result = SO_cast<otio::Composition>(self)->handles_of_child(SO_cast<otio::Composable>(composable), &aeh.error_status);

if (result.first) {
*hasLeft = true;
*rt1 = cxxRationalTime(*(result.first));
}
else {
*hasLeft = false;
}

if (result.second) {
*hasRight = true;
*rt2 = cxxRationalTime(*(result.second));
Expand Down Expand Up @@ -645,27 +692,27 @@ void media_reference_clear_available_range(CxxRetainer* self) {
// If true, value of passed in rect is set. If false, there was no media reference bounds
bool media_reference_available_image_bounds(CxxRetainer* self, CGRect* rect) {
std::optional<IMATH_NAMESPACE::Box2d> iBox2D = SO_cast<otio::MediaReference>(self)->available_image_bounds();

if (iBox2D) {
rect->origin.x = iBox2D->min.x;
rect->origin.y = iBox2D->min.y;
rect->size.width = iBox2D->max.x - iBox2D->min.x;
rect->size.height = iBox2D->max.y - iBox2D->min.y;

return true;
}

return false;
}

void media_reference_set_available_image_bounds(CxxRetainer* self, CGRect image_bounds) {
std::optional<IMATH_NAMESPACE::Box2d> iBox2D = std::optional<IMATH_NAMESPACE::Box2d>();

iBox2D->min.x = image_bounds.origin.x;
iBox2D->min.y = image_bounds.origin.y;
iBox2D->max.x = image_bounds.size.width + image_bounds.origin.x;
iBox2D->max.y = image_bounds.size.height + image_bounds.origin.y;

SO_cast<otio::MediaReference>(self)->set_available_image_bounds(iBox2D);
}

Expand Down Expand Up @@ -718,7 +765,7 @@ CxxTimeRange timeline_range_of_child(CxxRetainer* self, CxxRetainer* child, CxxE
}
return array;
}

NSArray* timeline_video_tracks(CxxRetainer* self) {
auto array = [NSMutableArray new];
for (auto t: SO_cast<otio::Timeline>(self)->video_tracks()) {
Expand Down Expand Up @@ -769,7 +816,7 @@ void effect_set_name(CxxRetainer* self, NSString* name) {
NSString* external_reference_get_target_url(CxxRetainer* self) {
return make_nsstring(SO_cast<otio::ExternalReference>(self)->target_url());
}

void external_reference_set_target_url(CxxRetainer* self, NSString* target_url) {
SO_cast<otio::ExternalReference>(self)->set_target_url([target_url UTF8String]);
}
Expand All @@ -782,7 +829,7 @@ void external_reference_set_target_url(CxxRetainer* self, NSString* target_url)
void generator_reference_set_generator_kind(CxxRetainer* self, NSString* kind) {
SO_cast<otio::GeneratorReference>(self)->set_generator_kind([kind UTF8String]);
}

void* generator_reference_parameters(CxxRetainer* self) {
return &SO_cast<otio::GeneratorReference>(self)->parameters();
}
Expand All @@ -791,7 +838,7 @@ void generator_reference_set_generator_kind(CxxRetainer* self, NSString* kind) {
double linear_time_warp_get_time_scalar(CxxRetainer* self) {
return SO_cast<otio::LinearTimeWarp>(self)->time_scalar();
}

void linear_time_warp_set_time_scalar(CxxRetainer* self, double time_scalar) {
SO_cast<otio::LinearTimeWarp>(self)->set_time_scalar(time_scalar);
}
Expand All @@ -806,7 +853,7 @@ void linear_time_warp_set_time_scalar(CxxRetainer* self, double time_scalar) {

void* algorithms_flatten_stack(CxxRetainer* in_stack, CxxErrorStruct* cxxErr) {
_AutoErrorHandler aeh(cxxErr);
return otio::flatten_stack(SO_cast<otio::Stack>(in_stack), &aeh.error_status);
return otio::flatten_stack(SO_cast<otio::Stack>(in_stack), &aeh.error_status);
}

void* algorithms_flatten_track_array(NSArray* tracks, CxxErrorStruct* cxxErr) {
Expand Down
2 changes: 1 addition & 1 deletion Sources/swift/Metadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ public enum Metadata {
return CxxAny(type_code: Int32(type.rawValue), value: value)
}

private static func withCxxAny(_ value: MetadataValue, work: (CxxAny) -> ()) {
static func withCxxAny(_ value: MetadataValue, work: (CxxAny) -> ()) {
switch value.metadataType {
case .none:
work(createCxxAny(.none, .init(i: 0)))
Expand Down
32 changes: 28 additions & 4 deletions Sources/swift/SerializableObjectWithMetadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,46 @@ public class SerializableObjectWithMetadata : SerializableObject {
}
}
}

override public var description: String {
let addr = ObjectIdentifier(self).hashValue
let addr2 = Int(bitPattern: cxxSerializableObject())
return "\(String(describing: type(of: self))) named '\(name)' <swift: 0x\(String(format: "%x", addr)), C++: \(String(format: "%p", addr2))>"
}

public var name: String {
get { return serializable_object_with_metadata_name(self) }
set { serializable_object_with_metadata_set_name(self, newValue) }
}

public var metadata: Metadata.Dictionary {
get { return Metadata.Dictionary.wrap(anyDictionaryPtr: serializable_object_with_metadata_metadata(self), cxxRetainer: self) }
}


public func getMetadataJSON(_ key: String) throws -> String? {
guard let value: MetadataValue = metadata[key] else {
return nil
}
var jsonString: String? = nil
var thrownError: Error? = nil
Metadata.withCxxAny(value) { cxxAny in
var mutableCxxAny = cxxAny
do {
jsonString = try OTIOError.returnOrThrow { any_value_to_json_string(&mutableCxxAny, 4, &$0) }
} catch {
thrownError = error
}
}
if let error = thrownError { throw error }
return jsonString
}

public func setMetadataJSON(_ key: String, _ value: String) throws {
var cxxAny = CxxAny()
_ = try OTIOError.returnOrThrow { any_value_from_json_string(value, &cxxAny, &$0) }
metadata[key] = Metadata.cxxAnyToMetadataValue(cxxAny)
}

override internal init(_ cxxPtr: CxxSerializableObjectPtr) {
super.init(cxxPtr)
}
Expand Down
Loading