Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 5 additions & 1 deletion Sources/objc/include/opentimelineio.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,11 @@ bool media_reference_is_missing_reference(CxxRetainer* self);
bool media_reference_available_range(CxxRetainer* self, CxxTimeRange*);
void media_reference_set_available_range(CxxRetainer* self, CxxTimeRange);
void media_reference_clear_available_range(CxxRetainer* self);


bool media_reference_available_image_bounds(CxxRetainer* self, CGRect* );
void media_reference_set_available_image_bounds(CxxRetainer* self, CGRect image_bounds);
void media_reference_clear_available_image_bounds(CxxRetainer* self);

// MARK: - Timeline
void* timeline_get_tracks(CxxRetainer* self);
void timeline_set_tracks(CxxRetainer* self, CxxRetainer* stack);
Expand Down
33 changes: 33 additions & 0 deletions Sources/objc/opentimelineio.mm
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,39 @@ void media_reference_clear_available_range(CxxRetainer* self) {
SO_cast<otio::MediaReference>(self)->set_available_range(std::nullopt);
}

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) {
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;
}

rect = NULL;
Comment thread
vade marked this conversation as resolved.
Outdated

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);
}

void media_reference_clear_available_image_bounds(CxxRetainer* self) {
SO_cast<otio::MediaReference>(self)->set_available_image_bounds(std::nullopt);
}


// MARK: - Timeline

void* timeline_get_tracks(CxxRetainer* self) {
Expand Down
19 changes: 19 additions & 0 deletions Sources/swift/MediaReference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,23 @@ public class MediaReference : SerializableObjectWithMetadata {
public var isMissingReference: Bool {
get { return media_reference_is_missing_reference(self) }
}

public var availableImageBounds: CGRect?
{
get {
var rect = CGRect(origin: CGPoint.init(x: 0, y: 0), size: CGSize(width: 0, height: 0))
return media_reference_available_image_bounds(self, &rect) ? rect : nil
}
set {
if let newValue = newValue {
Comment thread
vade marked this conversation as resolved.
Outdated

media_reference_set_available_image_bounds(self, newValue)
}
else
{
media_reference_clear_available_image_bounds(self)
}
}

}
}
29 changes: 29 additions & 0 deletions Tests/OpenTimelineIOTests/testTimeline.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,33 @@ final class testTimeline: XCTestCase {
XCTFail("Cannot read OTIO file `\(timelineInputPath)`: \(error)")
}
}

func testTimelineClipAvailableBounds() {
let inputName = "data/clip_example.otio"

guard let timelineInputPath = Bundle.module.path(forResource: inputName, ofType: "") else {
XCTFail("Missing test data `\(inputName)`")
return
}

do {
let otio = try SerializableObject.fromJSON(filename: timelineInputPath)

guard let timeline = otio as? Timeline else {
XCTFail("Could not create Timeline object from \(timelineInputPath)")
return
}

if let firstClip = timeline.videoTracks.first!.children[1] as? Clip,
let mediaReference = firstClip.mediaReference,
let availableBounds = mediaReference.availableImageBounds
{
XCTAssertEqual(availableBounds, CGRect(origin: .zero, size: CGSize(width: 16, height: 9)))
}

} catch let error {
XCTFail("Cannot read OTIO file `\(timelineInputPath)`: \(error)")
}
}

}
139 changes: 139 additions & 0 deletions Tests/data/clip_example.otio
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
{
"OTIO_SCHEMA": "Timeline.1",
"metadata": {},
"name": "transition_test",
"tracks": {
"OTIO_SCHEMA": "Stack.1",
"children": [
{
"OTIO_SCHEMA": "Track.1",
"children": [
{
"OTIO_SCHEMA": "Gap.1",
"effects": [],
"markers": [],
"enabled": true,
"metadata": {},
"name": "Gap A",
"source_range": {
"OTIO_SCHEMA": "TimeRange.1",
"duration": {
"OTIO_SCHEMA": "RationalTime.1",
"rate": 24,
"value": 8
},
"start_time": {
"OTIO_SCHEMA": "RationalTime.1",
"rate": 24,
"value": 0
}
}
},
{
"OTIO_SCHEMA": "Clip.1",
"effects": [],
"markers": [],
"enabled": true,
"media_reference": {
"OTIO_SCHEMA": "MissingReference.1",
"available_range": {
"OTIO_SCHEMA": "TimeRange.1",
"duration": {
"OTIO_SCHEMA": "RationalTime.1",
"rate": 24,
"value": 8
},
"start_time": {
"OTIO_SCHEMA": "RationalTime.1",
"rate": 24,
"value": 0
}
},
"metadata": {},
"available_image_bounds": {
"OTIO_SCHEMA": "Box2d.1",
"min": {
"OTIO_SCHEMA":"V2d.1",
"x": 0.0,
"y": 0.0
},
"max": {
"OTIO_SCHEMA":"V2d.1",
"x": 16.0,
"y": 9.0
}
},
"name": null
},
"metadata": {},
"name": "Clip-001",
"source_range": {
"OTIO_SCHEMA": "TimeRange.1",
"duration": {
"OTIO_SCHEMA": "RationalTime.1",
"rate": 24,
"value": 3
},
"start_time": {
"OTIO_SCHEMA": "RationalTime.1",
"rate": 24,
"value": 3
}
}
},
{
"OTIO_SCHEMA": "Transition.1",
"metadata": {},
"name": "Dissolve",
"transition_type": "SMPTE_Dissolve",
"parameters": {},
"in_offset": {
"OTIO_SCHEMA": "RationalTime.1",
"rate": 24,
"value": 2
},
"out_offset": {
"OTIO_SCHEMA": "RationalTime.1",
"rate": 24,
"value": 1
}
},
{
"OTIO_SCHEMA": "Gap.1",
"effects": [],
"markers": [],
"enabled": true,
"metadata": {},
"name": "Gap B",
"source_range": {
"OTIO_SCHEMA": "TimeRange.1",
"duration": {
"OTIO_SCHEMA": "RationalTime.1",
"rate": 24,
"value": 8
},
"start_time": {
"OTIO_SCHEMA": "RationalTime.1",
"rate": 24,
"value": 0
}
}
}
],
"effects": [],
"kind": "Video",
"markers": [],
"enabled": true,
"metadata": {},
"name": "Track-001",
"source_range": null
}
],
"effects": [],
"markers": [],
"enabled": true,
"metadata": {},
"name": "tracks",
"source_range": null
}
}