ORIAnnotations

This module is a set of helper classes to manage the media, and annotations.

The goal is to use OTIO as the interchange format for annotations, so that it could be used without needing any special tools. However, its not particularly helpful to directly read the OTIO file if you are trying to import the annotations into a production tracking system, and similarly to correctly create the OTIO file. So the classes below are used to help create and interpret the OTIO file.

graph TD ReviewGroup -- contains --> Media ReviewGroup -- contains --> Review Review -- contains --> ReviewItem ReviewItem -- contains --> Media ReviewItem -- contains --> ReviewItemFrame ReviewItemFrame -- uses --> SyncEvent Media -- creates --> OTIOClip ReviewItemFrame -- creates --> OTIOClip Review -- creates --> OTIOTrack ReviewGroup -- creates --> OTIOTimeline subgraph OpenTimelineIO OTIOClip OTIOTrack OTIOTimeline SyncEvent end
At a high-level:
  • ReviewGroup has a single set of Media which is being reviewed, and one or more Reviews (although typically 1).

  • Each Review has a single ReviewItem with a 1-1 relationship to the media.

  • Each ReviewItem can have either an overall note, or annotations or notes per frame, defined by a ReviewItemFrame

  • Each ReviewItemFrame could be a single PNG file of the annotation, or it could be the instructions to create those annotations using the ORI SyncEvent format.

TODO:
  • The biggest missing part is that we currently assume all media elements are movies, we need to be able to support frame-sequences too.

  • We also need to be given a OTIO Track, as a starting point, to seed a ReviewGroup.

class ORIAnnotations.Media(name: str | None = None, media_path: str | None = None, frame_rate: float = (None,), duration: int = (None,), start_frame: int = (0,), vendor_name: str | None = None, artist_name: str | None = None, vendor_id: str | None = None, client_id: str | None = None, clip_uuid: str | None = None, otio_clip: Clip | None = None)[source]

Bases: object

The media class is the container for the media being reviewed. It will end up on its own track.

name

Name of the media, typically the file basename.

Type:

str

media_path

Full path to the location of the media.

Type:

str

frame_rate

The frame rate of the media

Type:

float

duration

Duration of the media

Type:

int

start_frame

Start frame.

Type:

int

vendor_name

The name of the vendor

Type:

str

artist_name

The artist name

Type:

str

vendor_id

The unique vendor id

Type:

str

client_id

The unique client id

Type:

str

clip_uuid

The UUID of the clip

Type:

str

artist_name: str = None
calc_otio_end_frame()[source]
calc_otio_start_frame()[source]
client_id: str = None
clip_uuid: str = None
duration: int = (None,)
frame_rate: float = (None,)
media_path: str = None
name: str = None
otio_clip: Clip = None
start_frame: int = (0,)
vendor_id: str = None
vendor_name: str = None
class ORIAnnotations.Review(title: str, review_start_time: ~datetime.datetime | None = None, participants: ~typing.List[str] = <factory>, location: str | None = None, notes: str | None = None, review_items: ~typing.List[~ORIAnnotations.ReviewItem] = <factory>)[source]

Bases: object

Top level review, treated as a separate timeline.

title

The title of the review

Type:

str

review_start_time

When did this review start, useful if there is no timestamp in the title.

Type:

datetime

participants

A list of partipants.

Type:

List[str]

location

Where did this review happen.

Type:

str

notes

Any other overall notes for the review, also in markdown format.

Type:

str

Review_items

The list of things being reviewed.

Type:

List[ReviewItem]

location: str = None
notes: str = None
otio_track_read(reviewgroup, timeline, track, mediamap)[source]
participants: List[str]
review_items: List[ReviewItem]
review_start_time: datetime = None
title: str
class ORIAnnotations.ReviewGroup(media: List[Media] | None = None, reviews: List[Review] | None = None)[source]

Bases: object

This is a container for a selection of media, and one or more review This will create a single OTIO file.

export_otio_timeline()[source]

Create an otio timeline of the whole reviewgroup

media: List[Media] = None
read_otio_timeline(timeline)[source]

Read from an existing timeline, creating a full datastructure from that timeline.

reviews: List[Review] = None
class ORIAnnotations.ReviewItem(media: ~ORIAnnotations.Media = <factory>, review_frames: ~typing.List[~ORIAnnotations.ReviewItemFrame] = <factory>)[source]

Bases: object

This is a single piece of reviewed media, there might be multiple notes and annotations on it.

media

A single piece of media associated with a list of things to be reviewed.

Type:

Media

review_frames

A list of ReviewItemFrames that we have notes on.

Type:

List[ReviewItemFrame]

media: Media
review_frames: List[ReviewItemFrame]
class ORIAnnotations.ReviewItemFrame(review_item: ~ORIAnnotations.ReviewItem, frame: int | None = None, duration: int = 1, note: str | None = None, status: str | None = None, annotation_renderer: str | None = None, annotation_image: str | None = None, ocio_annotation_color_space: str | None = None, canvas_size: ~typing.List[int] = <factory>, annotation_commands: ~typing.List[~opentimelineio.schemadef.SyncEvent.SyncEvent] = <factory>)[source]

Bases: object

The frame that is being reviewed for a particular piece of media. There will be at least one of: * A note * A annotated image * A set of annotated commands that should create the annotated image.

review_item

The Review item associated with these frames.

Type:

ReviewItem

frame

The frame that is being reviewed.

Type:

int

duration

The duration of the note, this is typically 1 frame, but it could be more.

Type:

int

note

The reviewers note, this should be in markdown format.

Type:

str

status

The status of the review, i.e. is it approved. Note, the task is stored on the media, so whether its a comp, or anim, etc.

Type:

str

annotation_renderer

If you have chosen to add the annotation commands, we need to know which renderer you were using, in case there are incompabilities between the renderers.

Type:

str

annotation_image

The path to the annotated image. Ideally this is just the annotations, or even better is a un-premultiplied PNG of the annotated image with an alpha, so you can choose whether you view just the annotation or both.

Type:

str

canvas_size

For the annotation_commands what are the units of the brush-strokes.

Type:

[width, height]

ocio_annotation_color_space

OCIO color space using the color-interop naming convention.

Type:

str

annotation_commands: List[SyncEvent]
annotation_image: str = None
annotation_renderer: str = None
canvas_size: List[int]
duration: int = 1
export_svg()[source]

Export a SVG of any annotations.

frame: int = None
note: str = None
ocio_annotation_color_space: str = None
review_item: ReviewItem
status: str = None
ORIAnnotations.find_overlapping_clips(source_clip, target_track)[source]

Find clips on target_track that overlap with source_clip on source_track.

Parameters:
  • source_clip (Clip) – A OTIO clip that we want to find the associated clips in the target_track

  • target_track (track) – The track we are looking for the associated clips in.

Returns:

The clip(s) that are in range.

Return type:

[Clip]