Skip to content

Commit 0f68578

Browse files
committed
Initial alpha release for evaluation by invite-only community.
0 parents  commit 0f68578

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+4779
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.swp
2+
*.pyc
3+
build*

EULA.pdf

127 KB
Binary file not shown.

Makefile

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# run all the unit tests
2+
test:
3+
python2.7 -m unittest discover tests
4+
5+
# run all the unit tests, stopping at the first failure
6+
test_first_fail:
7+
python2.7 -m unittest discover tests --failfast
8+
9+
# skip the timecode test that takes forever
10+
fast_test:
11+
env OTIO_FAST_TEST=1 python2.7 -m unittest discover tests
12+
13+
# remove pyc files
14+
clean:
15+
rm */*.pyc */*/*.pyc
16+
17+
# conform all files to pep8 -- WILL CHANGE FILES IN PLACE
18+
autopep8:
19+
find . -name "*.py" | xargs autopep8 --aggressive --in-place -r
20+
21+
# run the codebase through pep8
22+
pep8:
23+
@find . -name "*.py" | xargs pep8

README.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
OpenTimelineIO
2+
==============
3+
4+
PRE-RELEASE NOTICE
5+
-----------------
6+
7+
We intend to release OpenTimelineIO as an open source project. Prior to
8+
release, a few people (like you) have early access to the project. Please see
9+
the contact section at the bottom if you have questions about this.
10+
11+
Overview
12+
--------
13+
14+
OpenTimelineIO is an interchange format and API for editorial cut information.
15+
OTIO is not a container format for media, rather it contains information about
16+
the order and length of cuts and references to external media.
17+
18+
OTIO includes both a file format and an API for manipulating that format. It
19+
also includes a plugin architecture for writing adapters to convert
20+
from/to existing editorial timeline formats. It also implements a dependency-
21+
less library for dealing strictly with time, `opentime`.
22+
23+
You can provide adapters for your video editing tool or pipeline as needed.
24+
Each adapter allows for import/export between that proprietary tool and the
25+
OpenTimelineIO format.
26+
27+
Use Cases
28+
---------
29+
30+
- I have a timeline in Adobe Premiere, and I want to bring that cut into my
31+
in-house animation system.
32+
- I have a timeline in Avid Media Composer, and my Producer wants to know a
33+
full list of the media I'm using.
34+
- I am about to render a bunch of shots & I want to make sure my frame ranges
35+
match what Editorial is asking for (not too long or too short).
36+
- The Editor just added some cross dissolves and I need to know how many more
37+
frames (at head or tail) of which shots need to be rendered.
38+
- Legal needs a list of all the audio we're using (music, effects, dialogue) in
39+
the current cut.
40+
- TDs/Animators want to get a cut from Editorial for reference, and then splice
41+
their updated renders/recordings into that cut.
42+
- Editorial is working with proxy media (QuickTime, MXF, etc.) and I want to
43+
gather all the EXRs that correspond with that & bring those into Nuke.
44+
45+
Architecture
46+
------------
47+
48+
TODO: INSERT POINTER TO CONCEPTUAL ARCHITECTURE DOCUMENT
49+
50+
Adapters
51+
--------
52+
53+
OpenTimelineIO supports, or plans to support, conversion adapters for these
54+
formats:
55+
56+
### Final Cut Pro FCPXML Document ###
57+
58+
- TODO: Not yet implemented
59+
- https://developer.apple.com/library/mac/documentation/FinalCutProX/Reference/FinalCutProXXMLFormat/Introduction/Introduction.html
60+
61+
### Adobe Premiere Project ###
62+
63+
- TODO: Not yet implemented
64+
- TODO: Documentation?
65+
66+
### CMX3600 EDL ###
67+
68+
- Limited support
69+
- http://xmil.biz/EDL-X/CMX3600.pdf
70+
71+
### Avid AAF ###
72+
73+
- TODO: Not yet implemented
74+
- http://www.amwa.tv/downloads/specifications/aafobjectspec-v1.1.pdf
75+
- http://www.amwa.tv/downloads/specifications/aafeditprotocol.pdf
76+
77+
Installing
78+
----------
79+
80+
run:
81+
```
82+
python setup.py install
83+
```
84+
85+
To build and install the project.
86+
87+
Makefile
88+
--------
89+
90+
Even though the project is python, we provide a makefile with some utility targets. These include targets for running unit tests and for running pep8/autopep8 to conform to style guide.
91+
92+
Developing
93+
----------
94+
95+
Currently the code base is written against python2.7. Before committing please run your changes through pep8/autopep8.
96+
97+
Contact
98+
-------
99+
100+
For more information, please visit http://opentimeline.io/
101+
or https://github.com/PixarAnimationStudios/OpenTimelineIO
102+

bin/otiocat.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/usr/bin/env python2.7
2+
3+
import argparse
4+
5+
import opentimelineio as otio
6+
7+
__doc__ = """ Print the contents of an OTIO file to stdout. """
8+
9+
10+
def _parsed_args():
11+
""" parse commandline arguments with argparse """
12+
13+
parser = argparse.ArgumentParser(
14+
description=__doc__,
15+
formatter_class=argparse.ArgumentDefaultsHelpFormatter
16+
)
17+
parser.add_argument(
18+
'filepath',
19+
type=str,
20+
nargs='+',
21+
help='files to print the contents of'
22+
)
23+
24+
return parser.parse_args()
25+
26+
27+
def _cat_otio_file(fpath):
28+
""" use the pretty print string adapter on the file. """
29+
30+
adapter = otio.adapters.from_name("pretty_print_string")
31+
return adapter.write_to_string(otio.adapters.read_from_file(fpath))
32+
33+
34+
def main():
35+
"""Parse arguments and call _cat_otio_file."""
36+
args = _parsed_args()
37+
38+
for fpath in args.filepath:
39+
print("fpath: {}".format(fpath))
40+
print(_cat_otio_file(fpath))
41+
42+
if __name__ == '__main__':
43+
main()

bin/otioconvert.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env python2.7
2+
3+
# python
4+
import argparse
5+
import sys
6+
7+
import opentimelineio as otio
8+
9+
__doc__ = """ Python wrapper around OTIO to convert timeline files between \
10+
formats.
11+
12+
Available adapters: {}
13+
""".format(otio.adapters.available_adapter_names())
14+
15+
16+
def _parsed_args():
17+
""" parse commandline arguments with argparse """
18+
19+
parser = argparse.ArgumentParser(
20+
description=__doc__,
21+
formatter_class=argparse.ArgumentDefaultsHelpFormatter
22+
)
23+
parser.add_argument(
24+
'-i',
25+
'--input',
26+
type=str,
27+
required=True,
28+
help='path to input file',
29+
)
30+
parser.add_argument(
31+
'-o',
32+
'--output',
33+
type=str,
34+
required=True,
35+
help='path to output file',
36+
)
37+
parser.add_argument(
38+
'-I',
39+
'--input-adapter',
40+
type=str,
41+
default=None,
42+
help="Instead of inferring the adapter to use, pick from the list.",
43+
)
44+
parser.add_argument(
45+
'-O',
46+
'--output-adapter',
47+
type=str,
48+
default=None,
49+
help="Instead of inferring the adapter to use, pick from the list.",
50+
)
51+
parser.add_argument(
52+
'-T',
53+
'--tracks',
54+
type=str,
55+
default=None,
56+
help="Pick one or more tracks, by 0-based index, separated by commas.",
57+
)
58+
59+
return parser.parse_args()
60+
61+
62+
def main():
63+
""" Parse arguments and convert the files. """
64+
65+
args = _parsed_args()
66+
67+
in_adapter = args.input_adapter
68+
if in_adapter is None:
69+
otio.adapters.from_filepath(args.input)
70+
71+
out_adapter = args.output_adapter
72+
if out_adapter is None:
73+
otio.adapters.from_filepath(args.output)
74+
75+
result_tl = otio.adapters.read_from_file(args.input, in_adapter)
76+
77+
if args.tracks:
78+
result_tracks = []
79+
for track in args.tracks.split(","):
80+
result_tracks.append(result_tl.tracks[int(track)])
81+
result_tl.tracks = result_tracks
82+
83+
otio.adapters.write_to_file(result_tl, args.output, out_adapter)
84+
85+
if __name__ == '__main__':
86+
try:
87+
main()
88+
except otio.exceptions.OTIOError as err:
89+
sys.stderr.write("ERROR: " + str(err) + "\n")
90+
sys.exit(1)

examples/conform.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
Example OTIO script that reads a timeline and then relinks clips
5+
to movie files found in a given folder, based on matching names.
6+
7+
Demo:
8+
9+
% ls -1R
10+
editorial_cut.otio
11+
media/
12+
shot1.mov
13+
shot17.mov
14+
shot99.mov
15+
16+
% conform.py -i editorial_cut.otio -f media -o conformed.otio
17+
Relinked 3 clips to new media.
18+
Saved conformed.otio with 100 clips.
19+
20+
% diff editorial_cut.otio conformed.otio
21+
...
22+
23+
"""
24+
25+
import argparse
26+
import glob
27+
import os
28+
29+
import opentimelineio as otio
30+
31+
32+
def parse_args():
33+
""" parse arguments out of sys.argv """
34+
parser = argparse.ArgumentParser(description=__doc__)
35+
parser.add_argument(
36+
'-i',
37+
'--input',
38+
type=str,
39+
required=True,
40+
help='Timeline file(s) to read. Any format supported by OTIO will'
41+
' work.'
42+
)
43+
parser.add_argument(
44+
'-f',
45+
'--folder',
46+
type=str,
47+
required=True,
48+
help='Folder to look for media in.'
49+
)
50+
parser.add_argument(
51+
'-o',
52+
'--output',
53+
type=str,
54+
required=True,
55+
help="Timeline file to write out."
56+
)
57+
return parser.parse_args()
58+
59+
60+
def _find_matching_media(name, folder):
61+
""" Look for media with this name in this folder. """
62+
63+
# In this case we're looking in the filesystem.
64+
# In your case, you might want to look in your asset management system
65+
# and you might want to use studio-specific metadata in the clip instead
66+
# of just the clip name.
67+
# Something like this:
68+
# shot = asset_database.find_shot(clip.metadata['mystudio']['shotID'])
69+
# new_media = shot.latest_render(format='mov')
70+
71+
matches = glob.glob("{0}/{1}.*".format(folder, name))
72+
matches = map(os.path.abspath, matches)
73+
74+
if len(matches) == 0:
75+
# print "DEBUG: No match for clip '{0}'".format(name)
76+
return None
77+
if len(matches) == 1:
78+
return matches[0]
79+
else:
80+
print "WARNING: {0} matches found for clip '{1}', using '{2}'".format(
81+
len(matches),
82+
name,
83+
matches[0]
84+
)
85+
return matches[0]
86+
87+
88+
def _conform_timeline(timeline, folder):
89+
""" Look for replacement media for each clip in the given timeline.
90+
The clips are relinked in place if media with a matching name is found.
91+
"""
92+
93+
count = 0
94+
95+
for clip in timeline.each_clip():
96+
# look for a media file that matches the clip's name
97+
new_path = _find_matching_media(clip.name, folder)
98+
99+
# if no media is found, keep going
100+
if not new_path:
101+
continue
102+
103+
# if we found one, then relink to the new path
104+
clip.media_reference = otio.media_reference.External(
105+
target_url="file://" + new_path,
106+
available_range=None # we don't know the available range
107+
)
108+
count += 1
109+
110+
return count
111+
112+
113+
def main():
114+
args = parse_args()
115+
116+
timeline = otio.adapters.read_from_file(args.input)
117+
count = _conform_timeline(timeline, args.folder)
118+
print "Relinked {0} clips to new media.".format(count)
119+
otio.adapters.write_to_file(timeline, args.output)
120+
print "Saved {} with {} clips.".format(
121+
args.output,
122+
len(list(timeline.each_clip()))
123+
)
124+
125+
if __name__ == '__main__':
126+
main()

0 commit comments

Comments
 (0)