Skip to content

1.5.0 — BRAW container metadata, ExifTool/ffprobe parity

Choose a tag to compare

@aagedal aagedal released this 01 May 20:45
· 99 commits to main since this release

Added

  • Blackmagic RAW (.braw) container metadata — new format support routed through MP4Parser. BRAW is an ISOBMFF derivative with the legacy QuickTime layout (wide + mdat head, moov tail-placed, no ftyp); the parser tolerates the missing ftyp and the mdta decoder grew handlers for BRAW's typed payloads including the BMD-specific type 71 (float32-BE pair) used for rectangle fields. Surfaces to CameraMetadata: camera make/model + firmware, color science generation, viewing gamma + gamut, compression ratio, shutter type; off-speed captureFps (distinct from the mvhd/stts-derived frameRate); production slate (clip number / scene / take / reel / camera / environment / day-night); sensor area, crop / safe-area rectangles, LUT used, post-3DLUT mode, embedded LUT name, frameguide aspect ratio, gamut compression. Per-frame interpretation (white point, tint, absolute ISO, shutter angle) lives in proprietary bfdn / ctrn boxes inside the codec sample entry and remains unparsed. Verified against Pyxis 12K / 6K and Cinema 6K samples.
  • MPEG-TS bitstream decoding — MPEGReader now decodes inline H.264 / HEVC SPS, AAC ADTS frame headers, and PCR timestamps directly from Transport Stream packets, surfacing pixel format, profile/level, framerate, sample rate, channel layout, and timing on .ts / .m2ts files without ffprobe. New MPEGBitstream.swift houses the bit-readers (Exp-Golomb, NAL emulation-prevention unescaping, ADTS frame parsing).
  • SMPTE ST 377-4 MCA audio labels for MXF — multichannel audio labeling per SMPTE ST 377-4 is now decoded out of MXF audio descriptors. New MCAAudioLabeling, MCALabelsRenderer, MXFMCAReader, surfaced through VideoStream / VideoMetadata and the JSON exporter. New CLI subcommand swift-exif mxf-labels emits a bmx-compatible labels.txt round-trip for production audio workflows.
  • Apple ecosystem support (Phase 18) — AppleMakerNote.swift (iPhone MakerNote: lens model, ContentIdentifier, image stabilization, HDR mode, …), AAESidecar.swift (Apple Photos .aae adjustment XML), HEIFAuxiliaryImages.swift (depth maps, alpha mattes, HDR gain maps via shared ISOBMFF / iloc), and Live Photo ContentIdentifier surfaced from MP4Parser.
  • Pentax, Leica, and Sigma MakerNote parsers — three additional vendor MakerNote implementations with matching writer support and round-trip test coverage.
  • ExifTool / ffprobe parity initiative — PARITY_PLAN.md plus the first phases:
    • HEIC parity (Phase 1) — infe-driven content_type, explicit meta → iprp → ipco walk, top-level colr fallback.
    • JPEG XL (Phase 2) — decode SizeHeader from the JXL codestream so File:ImageWidth / Height are populated.
    • MP4 streams (Phase 3.1 / 3.2 / 3.5) — preserve track declaration order in streams, surface data tracks, hoist chapter tracks out of streams into a sibling chapters array.
    • MP3 / M4A streams (Phase 3.3) — emit a single synthetic audio stream from --streams to match ffprobe.
    • MKV track order (Phase 3.4) — preserve Matroska track declaration order.
    • GPS / subtitle codec cosmetics (Phase 4) — render GPS coordinates with degree signs, alias tx3g to mov_text.

Changed

  • Format-level duration now matches ffprobe. Previously format.duration was mvhd verbatim; mvhd is the longest mdhd of any track, so files like ChapterMarkerDualSubtitle.mp4 reported 98.691 s while audio/video both ended at ~71.16 s. The MP4 reader now caps mvhd at max(audio, video) when subtitle/data tracks inflate it, and keeps the smaller mvhd value untouched when edit-list trimming legitimately makes it shorter than the longest essence stream.
  • Audio file format.bit_rate now matches ffprobe. For MP3 / M4A / FLAC, the container bit_rate is now derived as file_size × 8 / duration (whole-file rate including container overhead and AAC priming/postroll padding) instead of the audio stream's declared rate.
  • MXF and MPEG-TS per-stream Duration. MXF essence descriptors and MPEG-TS streams don't carry per-track durations the way MP4 does. The format-level duration is now propagated to streams that don't already have one (matching ffprobe behaviour); legitimate per-stream durations are never overwritten.
  • GPMF SCAL divisor lookup is now hoisted out of the per-sample GPS5 loop in GPMFReader — pure refactor, behavior preserved.

Fixed

  • GIF parser sub-block handling — regression tests added covering the earlier sub-block-overrun hardening (truncated extension blocks, malformed image descriptors, unterminated sub-block chains).

Tests

1420 tests, 0 failures (26 skipped), covering BRAW slate extraction across Pyxis 12K / 6K / Cinema 6K, the new MakerNote families, MXF MCA round-trip via bmx, MPEG-TS bitstream parity vs ffprobe, and HEIF auxiliary image extraction.