Read Adobe Premiere Pro project files (.prproj) without Premiere: sequences, tracks, clips,
in and out points, media paths, markers and the bin tree, as typed Python data. Convert any
sequence to an OpenTimelineIO timeline.
It is for developers of tools that need to open a Premiere project: subtitle editors, asset managers, conform and archive scripts, other editors importing a Premiere edit. Read only, no runtime dependency, Python 3.9 and later.
pip install premiere-prproj-reader
pip install "premiere-prproj-reader[otio]" # with the OpenTimelineIO adapterThe package ships two small projects saved by Premiere Pro 26.3, so this runs as written:
import premiere_prproj_reader as prproj
project = prproj.read(prproj.samples.path("markers"))
print(project.version) # 45, the project format of Premiere Pro 26.3
for sequence in project.sequences:
print(sequence.name, sequence.frame_rate, f"{sequence.width}x{sequence.height}")
for track in sequence.tracks:
for item in track.items:
start = prproj.timecode(item.start_ticks, sequence.frame_rate)
end = prproj.timecode(item.end_ticks, sequence.frame_rate)
print(" ", track.label, start, end, item.name)Seq A 30000/1001 64x36
V1 00:00:00:00 00:00:04:29 red_64x36.bmp
A1 00:00:04:29 00:00:05:28 tone_440_1s.wav
Seq B 30000/1001 64x36
V1 00:00:00:00 00:00:05:28 Seq A
A1 00:00:00:00 00:00:05:28 Seq A
read() takes a path, the file's bytes or a binary file object, gzip-compressed or plain XML.
import premiere_prproj_reader as prproj
project = prproj.read(prproj.samples.path("markers"))
for media in project.media:
print(media.title, media.path, media.relative_path, "offline" if media.offline else "")path is the absolute path Premiere last resolved, relative_path the one relative to the project
file. Generated media (Black Video, color mattes, bars and tone) has generated=True and no path.
import premiere_prproj_reader as prproj
project = prproj.read(prproj.samples.path("markers"))
outer = project.find_sequence("Seq B")
item = outer.video_tracks[0].items[0]
print(item.in_point_ticks, item.out_point_ticks, item.speed, item.enabled)
if item.sequence_id is not None:
nested = project.sequence_by_id(item.sequence_id)
print("nests", nested.name)Every time is an integer count of Premiere ticks (254,016,000,000 per second), so nothing is lost
to rounding. ticks_to_seconds, ticks_to_frames and timecode convert them; frame rates are
exact Fractions (29.97 is 30000/1001). in_point_ticks and out_point_ticks are in the
source's own time, so for a clip at 50 percent speed the source range is half the timeline length.
import premiere_prproj_reader as prproj
project = prproj.read(prproj.samples.path("markers"))
for marker in project.find_sequence("Seq A").markers:
seconds = prproj.ticks_to_seconds(marker.start_ticks)
print(f"{seconds:.2f}s", marker.type, marker.name, marker.comment, marker.url or "")Sequence markers and clip markers carry name, comment, start, duration, type (Comment, Chapter, Segmentation, WebLink, FlashCuePoint) and the URL of a web link.
import premiere_prproj_reader as prproj
project = prproj.read(prproj.samples.path("markers"))
for entry in project.root.walk():
kind = "bin" if isinstance(entry, prproj.Bin) else "clip"
print(kind, entry.name)With the otio extra installed:
import opentimelineio as otio
import premiere_prproj_reader as prproj
from premiere_prproj_reader.otio import to_timeline
project = prproj.read(prproj.samples.path("markers"))
timeline = to_timeline(project.find_sequence("Seq A"), project)
print(otio.adapters.write_to_string(timeline, "otio_json")[:80])Installing the otio extra also registers a prproj adapter, so OpenTimelineIO tools read
projects directly:
import opentimelineio as otio
timeline = otio.adapters.read_from_file("edit.prproj")From there, OpenTimelineIO and its adapter plugins write the timeline to the other formats they support (Final Cut Pro XML, CMX 3600 EDL and more).
prproj info edit.prproj # versions, sequences, tracks
prproj json edit.prproj # the whole project as JSON
prproj otio edit.prproj edit.otio --sequence "Main edit"Editors and subtitle tools written in other languages can call the CLI and read its JSON instead of
keeping their own .prproj parser:
prproj json edit.prproj > edit.json{"version": 45, "build": "26.3.0x93 - 20/07/2026 14:03:26",
"sequences": [{"id": "9c19c828-...", "name": "Seq A", "frame_rate": "30000/1001",
"width": 64, "height": 36,
"video_tracks": [{"kind": "video", "index": 0, "muted": false, "locked": false,
"items": [{"name": "red_64x36.bmp", "start_ticks": 0, "end_ticks": 1262874412800,
"in_point_ticks": 914456685542400, "out_point_ticks": 915719559955200,
"speed": 1.0, "enabled": true, "sequence_id": null, "markers": [],
"media": {"title": "red_64x36.bmp", "path": "C:\\...\\red_64x36.bmp",
"relative_path": "..\\assets\\red_64x36.bmp", "offline": false,
"generated": false}}]}],
"audio_tracks": [], "markers": [{"name": "chapter", "type": "Chapter",
"start_ticks": 254016000000, "duration_ticks": 0, "comment": "", "url": null}]}],
"media": [], "root": {"name": "", "children": []}}(Shortened.) Ticks divide by 254,016,000,000 for seconds. A subtitle editor that needs the marker
list, or an editor importing a Premiere timeline, maps sequences[].markers and
sequences[].video_tracks[].items[] directly; an editor that already reads OpenTimelineIO can use
prproj otio edit.prproj edit.otio instead.
The tests read projects saved by Premiere Pro from 2.0 (project format 18, 2006) to 26.3 (format
45, 2026): format 18, 19 (CS3), 35 (11.1), 38 (14.0), 42 (24.4), 43 (25.2) and 45 (26.3). The
element names this reader follows are the same across all of them. Older formats are skeletons
reduced from real projects by scripts/reduce_fixture.py (every name and path replaced); the
format 45 projects are the py-premiere sample set (MIT), and the test suite checks this library
against the values Premiere's own ExtendScript reported for them (tests/fixtures/truth/).
If a project of yours does not read, python scripts/drift_check.py DIR reports what failed, and
scripts/reduce_fixture.py makes a shareable copy for a bug report.
| premiere-prproj-reader | py-premiere | prproj-parser | otio-premiereproject | prproj-rs | |
|---|---|---|---|---|---|
| Scope | read only, plain data | read and write, ExtendScript-shaped object model | read only | OpenTimelineIO adapter | Rust parser |
| Formats tested | 18 to 45 (Premiere Pro 2.0 to 26.3) | Premiere Pro 26.3 samples | 2023 to 2026, per its README | not stated | one project in test_files/ |
| Checked against Premiere's ExtendScript values | yes (tests/fixtures/truth/) |
yes, per its README | not stated | not stated | not stated |
| OpenTimelineIO | to_timeline and an adapter plugin |
no | no | yes | no |
| Markers, bin tree, source in and out points | yes | yes | not in its API table | in and out points only | no |
| Last change | 2026 | 2026 | 2026 | 2021 | 2023 |
The other columns come from each project's README and source as read on 2026-11-02.
Pick py-premiere when you need to write projects or read effects, keyframes and masks. Pick this one when you want a small dependency-free reader whose output is plain frozen dataclasses, exact ticks, and an OpenTimelineIO timeline, tested across twenty years of Premiere versions.
Projects come from users. The reader refuses XML carrying a DOCTYPE or ENTITY declaration
(including one hidden by a UTF-16 or UTF-32 encoding), caps the decompressed size
(read(..., max_bytes=...), 1 GiB by default) and bin nesting, and raises PrprojError on
malformed numbers or references instead of crashing with another exception.
MIT. The sample projects in src/premiere_prproj_reader/samples/ and tests/fixtures/v45_* come from
py-premiere (MIT, Copyright (c) 2026 Aurore Delaunay); its licence is kept beside them.