Skip to main content

framewright

A drop-in replacement for cv::VideoCapture and cv::VideoWriter that gives you frame-precise seeking, color space control, HDR10 writing, and lossless encoding.

Available for C++, Python, and JavaScript — Node.js and browsers via WebAssembly (see wasm/README.md).

What framewright adds over OpenCV

Reading

Feature OpenCV framewright
Frame-precise seeking Forward only, not frame-accurate Forward and backward, keyframe-accelerated
Color space control Opaque, implementation-defined Explicit BT.709/BT.601 selection, full/limited range override
Color metadata Not exposed getColorSpace(), getColorRange(), getPixelFormat(), getCodecID()
Zero-copy frames No readRef() avoids per-frame clone
Untagged content Implementation-defined matrix Sensible defaults (BT.709 for HD, BT.601 for SD)
HDR sources (PQ/HLG) Washed-out colors, no warning Opt-in tone mapping to SDR, or full-precision code values via read16()

Writing

Feature OpenCV framewright
HDR10 output Not supported HEVC 10-bit with BT.2020, PQ, mastering display metadata
Lossless encoding Not supported FFV1 (RGB, no YUV loss), H.264 qp=0 with 4:4:4
10-bit SDR Not supported HEVC Main10 with BT.709 for high-precision intermediates
Color space control Opaque Explicit BT.709/BT.2020, full/limited range
QuickTime compatibility Varies hvc1 codec tag for Safari/QuickTime HDR playback

Verified accuracy

Measured by reading BT.709-tagged lossless test videos with both libraries (OpenCV 4.13.0 and framewright on macOS). Both produce identical pixel values when metadata is present — framewright adds control, not a different answer:

cmake -B build -DFRAMEWRIGHT_BUILD_EXAMPLES=ON && cmake --build build
./build/compare_readers your_video.mp4

Migrating from OpenCV

framewright is a drop-in replacement. The API follows the same conventions (BGR cv::Mat frames):

Reading

// OpenCV
cv::VideoCapture cap("video.mp4");
cv::Mat frame;
cap.read(frame);

// framewright — same API, more capabilities
framewright::VideoReader reader;
reader.open("video.mp4");
cv::Mat frame;
reader.read(frame);

// seek backward (not possible with cv::VideoCapture)
reader.seek(0);
reader.read(frame);

// inspect color metadata
std::cout << "Color space: " << reader.getColorSpace() << std::endl;
std::cout << "Pixel format: " << av_get_pix_fmt_name(reader.getPixelFormat()) << std::endl;

Writing

// OpenCV
cv::VideoWriter w("out.mp4",
    cv::VideoWriter::fourcc('a','v','c','1'),
    30, cv::Size(1920, 1080));
w.write(frame);

// framewright — same pattern, more control
framewright::VideoWriter w;
w.open("out.mp4", AV_CODEC_ID_H264, 1920, 1080, {30, 1});
w.write(frame);
w.release();

Property mapping

OpenCV framewright
cap.get(CAP_PROP_FRAME_WIDTH) reader.getWidth()
cap.get(CAP_PROP_FRAME_HEIGHT) reader.getHeight()
cap.get(CAP_PROP_FPS) reader.getFPS()
cap.get(CAP_PROP_FRAME_COUNT) reader.getFrameCount()
cap.get(CAP_PROP_POS_FRAMES) reader.getCurrentFrameNumber()

Quick start

C++

#include <framewright/framewright.h>

// Read with correct BT.709 color conversion
framewright::VideoReader reader;
reader.open("input.mp4", /*force_bt709=*/true);

cv::Mat frame;
while (reader.read(frame)) {
    // frame is BGR cv::Mat with correct pixel values
}

// Write HDR10 HEVC
framewright::VideoWriterOptions opts;
opts.pix_fmt = AV_PIX_FMT_YUV420P10LE;
opts.is_10bit = true;

framewright::VideoWriter writer;
writer.open("output.mp4", AV_CODEC_ID_HEVC, 3840, 2160,
            {60000, 1001}, opts);  // 59.94 fps
writer.write(hdr_frame);  // CV_16UC3 BGR
writer.release();

Python

import framewright

reader = framewright.VideoReader()
reader.open("input.mp4", force_bt709=True)
for frame in reader:  # numpy (H, W, 3) uint8 BGR
    print(frame.shape, frame.dtype)

writer = framewright.VideoWriter()
writer.open("output.mp4", codec="h264", width=1920, height=1080, fps=30)
writer.write(frame)
writer.release()

Reading HDR video

HDR sources (BT.2020 with PQ/SMPTE 2084 or HLG transfer) always get the correct BT.2020 color matrix. Beyond the matrix you have three choices:

// 1. Display-ready SDR: linearize PQ/HLG, tone map (peak from the source's
//    mastering metadata when present, 1000 nits otherwise), convert BT.2020
//    primaries to BT.709, encode with BT.709 gamma.
framewright::VideoReaderOptions opts;
opts.hdr_mode = framewright::HdrMode::ToneMapSDR;
reader.open("hdr10.mp4", opts);
reader.read(frame);   // CV_8UC3, looks right on an SDR display

// 2. Full-precision code values for your own pipeline: the transfer function
//    is NOT applied, so PQ/HLG data stays encoded, at 16-bit precision.
reader.open("hdr10.mp4");
reader.read16(frame); // CV_16UC3; pair with getColorTransfer()/getColorPrimaries()

// 2b. Linear light for image math: transfer function removed (PQ/HLG/SDR),
//     float BGR normalized so 1.0 == SDR reference white (100 nits).
//     HDR highlights exceed 1.0. Primaries unchanged.
reader.readLinear(frame); // CV_32FC3

// 3. Default read() is unchanged: matrix-only conversion. For HDR sources the
//    result remains HDR-encoded (washed out as sRGB) and a warning is logged.

Python: reader.open("hdr10.mp4", tone_map_hdr=True), reader.read16(), reader.read_linear().

New to color management? docs/COLOR.md explains matrices, range, primaries, transfer functions, linear light, and tone mapping — and which framewright call gives you which.

Only codec-level color metadata is honored. Frame-level dynamic metadata (HDR10+, Dolby Vision RPUs) is ignored: Dolby Vision profile 5 content (ICtCp) decodes with approximated colors and a warning.

Building

As a dependency (CMake FetchContent)

include(FetchContent)
FetchContent_Declare(
    framewright
    GIT_REPOSITORY https://github.com/kmatzen/framewright.git
    GIT_TAG main
)
FetchContent_MakeAvailable(framewright)

target_link_libraries(your_target PRIVATE framewright::framewright)

Standalone

mkdir build && cd build
cmake .. -DFRAMEWRIGHT_BUILD_EXAMPLES=ON
make -j$(nproc)

Python

pip install framewright

Requirements

  • C++17 compiler
  • OpenCV 4.0+
  • FFmpeg 4.2+ (libavformat, libavcodec, libswscale, libavutil)

Logging

By default, framewright only logs errors. To see informational output:

framewright::setLogLevel(framewright::LogLevel::Info);     // See everything
framewright::setLogLevel(framewright::LogLevel::Error);    // Errors only (default)
framewright::setLogLevel(framewright::LogLevel::Quiet);    // Silence all output

API

framewright::VideoReader

Method Description
open(filename, force_bt709, force_full_range) Open a video file with optional color space overrides
open(filename, options) Open with VideoReaderOptions (color overrides + HdrMode)
read(frame) Read the next frame as BGR cv::Mat (cloned, always safe)
readRef(frame) Read the next frame without copying (valid until next read)
read16(frame) Read as CV_16UC3 with source code values preserved (no transfer applied)
readLinear(frame) Read as CV_32FC3 linear light (1.0 = SDR white, source primaries)
hasHDR10Metadata(), getHDR10Metadata() HDR10 static metadata from the source (drives the tone-map peak)
seek(frame_number) Seek to a frame (forward and backward)
getPixelFormat(), getCodecID() Source format info
getColorSpace(), getColorRange() Color metadata
getColorPrimaries(), getColorTransfer() HDR-relevant color metadata
isToneMappingActive() Whether read() is tone mapping this source
getFPS(), getWidth(), getHeight() Video properties

framewright::VideoWriter

Method Description
open(filename, codec_id, w, h, fps, opts) Open output with full codec control
write(frame) Write a BGR frame (CV_8UC3 or CV_16UC3, display-encoded)
writeLinear(frame) Write a CV_32FC3 linear-light frame (PQ-encoded in HDR mode, BT.709 in SDR)
setHDR10Metadata(metadata) Set mastering display / content light level
release() Flush and finalize the file

framewright::VideoWriterOptions

Field Default Description
bitrate 25000000 Target bitrate in bits/sec
pix_fmt YUV420P Output pixel format
is_10bit false HDR10 mode (BT.2020 + PQ)
full_range false Full range (0-255) vs limited (16-235)
use_444 false 4:4:4 chroma (no subsampling)
lossless false Mathematically lossless encoding

Supported codecs: H.264, H.265/HEVC (8-bit and 10-bit), FFV1 (lossless RGB).

License

MIT

Metadata

Release files for framewright 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for framewright 0.2.0
File Size Uploaded
framewright-0.2.0.tar.gz 80.0 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for framewright 0.2.0
File
framewright-0.2.0-cp313-cp313-manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.28+ x86-64 Details
framewright-0.2.0-cp313-cp313-macosx_13_0_arm64.whl CPython 3.13 CPython 3.13 macOS 13.0+ ARM64 Details
framewright-0.2.0-cp312-cp312-manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.28+ x86-64 Details
framewright-0.2.0-cp312-cp312-macosx_13_0_arm64.whl CPython 3.12 CPython 3.12 macOS 13.0+ ARM64 Details
framewright-0.2.0-cp311-cp311-manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.28+ x86-64 Details
framewright-0.2.0-cp311-cp311-macosx_13_0_arm64.whl CPython 3.11 CPython 3.11 macOS 13.0+ ARM64 Details
framewright-0.2.0-cp310-cp310-manylinux_2_28_x86_64.whl CPython 3.10 CPython 3.10 Linux glibc 2.28+ x86-64 Details
framewright-0.2.0-cp310-cp310-macosx_13_0_arm64.whl CPython 3.10 CPython 3.10 macOS 13.0+ ARM64 Details
framewright-0.2.0-cp39-cp39-manylinux_2_28_x86_64.whl CPython 3.9 CPython 3.9 Linux glibc 2.28+ x86-64 Details
framewright-0.2.0-cp39-cp39-macosx_13_0_arm64.whl CPython 3.9 CPython 3.9 macOS 13.0+ ARM64 Details

Total release size: 85.2 MB

Release files / framewright-0.2.0.tar.gz

Download URL framewright-0.2.0.tar.gz
Size 80.0 kB
Tags Source
SHA-256 checksum
How to use checksums
f8086433b4e3bf0c471b66de17ee2114320b6417dad23ada496f94ce4680cc2c
BLAKE2b-256 checksum
How to use checksums
a0dfc5799664da91923789e9abef56925d1a050df31be05960790d56ff7ec40c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release files / framewright-0.2.0-cp313-cp313-manylinux_2_28_x86_64.whl

Download URL framewright-0.2.0-cp313-cp313-manylinux_2_28_x86_64.whl
Size 8.9 MB
Tags CPython 3.13 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
9485a6b8a68569e063dffef46bfae1b478587737dc7c57c8e0a1cd99188c7a96
BLAKE2b-256 checksum
How to use checksums
f8734f1e6d0aa1e547e2e66b71afe262102505a0e4c9ef41637f03f968996b00
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release files / framewright-0.2.0-cp313-cp313-macosx_13_0_arm64.whl

Download URL framewright-0.2.0-cp313-cp313-macosx_13_0_arm64.whl
Size 8.1 MB
Tags CPython 3.13 macOS 13.0+ ARM64
SHA-256 checksum
How to use checksums
e51eba11d3adfada6cd6ed4fad49a7af4277b8f1bce2e2d09bb4b886e120132f
BLAKE2b-256 checksum
How to use checksums
425d5bb49ffef96b7faf7ace76697362337bc024e86d64fedf3f3cda5737c3d4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release files / framewright-0.2.0-cp312-cp312-manylinux_2_28_x86_64.whl

Download URL framewright-0.2.0-cp312-cp312-manylinux_2_28_x86_64.whl
Size 8.9 MB
Tags CPython 3.12 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
2883c22171b1b1d8b26acec18d1166c1004081fa382eb9b952602bf6fbae5465
BLAKE2b-256 checksum
How to use checksums
b3689d2f897323d9fe8d2c58aaf35a87431972f602563771f9aae3ed8806bae3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release files / framewright-0.2.0-cp312-cp312-macosx_13_0_arm64.whl

Download URL framewright-0.2.0-cp312-cp312-macosx_13_0_arm64.whl
Size 8.1 MB
Tags CPython 3.12 macOS 13.0+ ARM64
SHA-256 checksum
How to use checksums
22e0d1ab914911bfd1bfc8522e36b9c6940e6e9d104aab27724d0fcd94a885d8
BLAKE2b-256 checksum
How to use checksums
ab3cb543d66e28791394bc37b156bda675445d742c5b9c45058901ea512cc955
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release files / framewright-0.2.0-cp311-cp311-manylinux_2_28_x86_64.whl

Download URL framewright-0.2.0-cp311-cp311-manylinux_2_28_x86_64.whl
Size 8.9 MB
Tags CPython 3.11 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
5f713b044a479e0a51dee21f10250e1023fcb93a8da0e9820ea511ad671060e3
BLAKE2b-256 checksum
How to use checksums
d8cba302a5bf10dd3edf6f9857e6ace1f706b0990f6ee8d01d9e2e3c0e3b4726
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release files / framewright-0.2.0-cp311-cp311-macosx_13_0_arm64.whl

Download URL framewright-0.2.0-cp311-cp311-macosx_13_0_arm64.whl
Size 8.1 MB
Tags CPython 3.11 macOS 13.0+ ARM64
SHA-256 checksum
How to use checksums
8018145a22d07f19c224b2cf0a56b98b0f74f2a08d4ad6c45f353d1f23491fdf
BLAKE2b-256 checksum
How to use checksums
3c069e41d7e704b6dfc7a035479b943a1f82616c4f32849b02323fddf864427d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release files / framewright-0.2.0-cp310-cp310-manylinux_2_28_x86_64.whl

Download URL framewright-0.2.0-cp310-cp310-manylinux_2_28_x86_64.whl
Size 8.9 MB
Tags CPython 3.10 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
ed2a740934081f05e7d53afe5290c2612113ab8e9299a027fccee27b380bbcd8
BLAKE2b-256 checksum
How to use checksums
08dbbd44e5cbb57f012cad28a681dff356f337b2a725a5563875e5608856ee4a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release files / framewright-0.2.0-cp310-cp310-macosx_13_0_arm64.whl

Download URL framewright-0.2.0-cp310-cp310-macosx_13_0_arm64.whl
Size 8.1 MB
Tags CPython 3.10 macOS 13.0+ ARM64
SHA-256 checksum
How to use checksums
3f87f235c89129c8ea1f98fa64cc87095174073b6e5d123d83320f7a32b30eb6
BLAKE2b-256 checksum
How to use checksums
a6774b34434b90e63b0bd5686c23788c15dfc8f60609e0c8bb49b622ae585035
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release files / framewright-0.2.0-cp39-cp39-manylinux_2_28_x86_64.whl

Download URL framewright-0.2.0-cp39-cp39-manylinux_2_28_x86_64.whl
Size 8.9 MB
Tags CPython 3.9 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
0831dc4cc780a6f6c73c8e5591900a8110dee6632e3dc6aaadcf9300779c152c
BLAKE2b-256 checksum
How to use checksums
93f40a5f0bacfaf8285b3444d759a23447371d6b783763a235eb109036c8b138
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release files / framewright-0.2.0-cp39-cp39-macosx_13_0_arm64.whl

Download URL framewright-0.2.0-cp39-cp39-macosx_13_0_arm64.whl
Size 8.1 MB
Tags CPython 3.9 macOS 13.0+ ARM64
SHA-256 checksum
How to use checksums
8fd28ee4378172aea8efa7cf407e5430f343f1477aea0e3138e507ef7306193d
BLAKE2b-256 checksum
How to use checksums
79b3f07cd7ed2bbd9444289e589b65fb0a0f213c3fe9826e086099f7eff66cd7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.1

16 release files

0.3.0

16 release files

This release

0.2.0 This release

11 release files

0.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page