--- a/Package.swift
+++ b/Package.swift
@@ -2,43 +2,22 @@
 
 import PackageDescription
 
+// AetherEngine 5.8.4, vendored from upstream revision
+// b05d384705792e949f22b0bd7c98ac8453cbd208. Local source changes and the
+// reduced target set are documented in UPSTREAM.md.
 let package = Package(
-    name: "AetherEngine",
+    name: "CloudVideoAetherEnginePackage",
     platforms: [
         .iOS(.v16),
         .tvOS(.v16),
         .macOS(.v14),
     ],
     products: [
-        .library(
-            name: "AetherEngine",
-            targets: ["AetherEngine"]
-        ),
-        .library(
-            name: "AetherEngineSMB",
-            targets: ["AetherEngineSMB"]
-        ),
-        // aetherctl is intentionally not exposed as a product. The target
-        // uses Foundation.Process, which is unavailable on tvOS/iOS, so
-        // exposing it would force SPM consumers to compile it on those
-        // platforms. The target is preserved below so `swift build` on
-        // macOS still produces the CLI for upstream development.
+        .library(name: "CloudVideoAetherEngine", targets: ["AetherEngine"]),
     ],
     dependencies: [
-        // Minimal FFmpeg build (avcodec, avformat, avutil, swresample only).
-        // No network stack, we use custom AVIO + URLSession for HTTP streams.
-        // Resolved over Git rather than a local path so consumers (and
-        // Xcode Cloud) can build without a sibling FFmpegBuild checkout.
-        .package(url: "https://github.com/superuser404notfound/FFmpegBuild", from: "2.1.0"),  // 2.1.0: yadif_videotoolbox + hwupload (Metal GPU deinterlace); 2.0.0: dynamic frameworks (LGPL), zvbi GPL excision
-        // Pure-Swift SMB2 client (MIT) that speaks the protocol over
-        // NWConnection. Replaces AMSMB2/libsmb2, which EPERMs on tvOS/iOS.
-        // Pinned to the 0.3.x minor: SMBClient is pre-1.0 with an actively
-        // moving API, so allow patch updates but not a minor bump.
-        .package(url: "https://github.com/kishikawakatsumi/SMBClient", .upToNextMinor(from: "0.3.1")),
-        // libdovi (Dolby Vision RPU parser/converter). Resolved over Git like
-        // FFmpegBuild so consumers (and Xcode Cloud) build without a sibling
-        // LibDovi checkout; the prebuilt xcframework needs no Rust at build time.
-        .package(url: "https://github.com/superuser404notfound/LibDovi", from: "1.0.2"),  // 1.0.2: iOS slices + x86_64 (Intel Macs)
+        .package(url: "https://github.com/superuser404notfound/FFmpegBuild", from: "2.1.0"),
+        .package(url: "https://github.com/superuser404notfound/LibDovi", from: "1.0.2"),
     ],
     targets: [
         .target(
@@ -56,28 +35,9 @@
                 .linkedFramework("AudioToolbox"),
             ]
         ),
-        .target(
-            name: "AetherEngineSMB",
-            dependencies: [
-                "AetherEngine",
-                .product(name: "SMBClient", package: "SMBClient"),
-            ],
-            path: "Sources/AetherEngineSMB"
-        ),
-        .executableTarget(
-            name: "aetherctl",
-            dependencies: ["AetherEngine", "AetherEngineSMB"],
-            path: "Sources/aetherctl"
-        ),
         .testTarget(
             name: "AetherEngineTests",
-            dependencies: ["AetherEngine"],
-            path: "Tests/AetherEngineTests"
+            dependencies: ["AetherEngine"]
         ),
-        .testTarget(
-            name: "AetherEngineSMBTests",
-            dependencies: ["AetherEngineSMB"],
-            path: "Tests/AetherEngineSMBTests"
-        ),
     ]
 )
--- a/Sources/AetherEngine/AetherEngine+Loading.swift
+++ b/Sources/AetherEngine/AetherEngine+Loading.swift
@@ -539,10 +539,9 @@
             try session.start()
         }.value
         #if os(iOS)
-        // AirPlay (#86): while external playback is active, serve the loopback over the device's LAN IP and
-        // force the media playlist, so the receiver reaches the engine-processed stream (DV/Atmos/subtitles
-        // preserved) and isn't handed a DV/HDR master it rejects on an SDR panel (DrHurt). Reverts on the
-        // reload when AirPlay ends.
+        // AirPlay (#86): while external playback is active, serve the loopback over the device's LAN IP. A
+        // source master becomes the reduced master so native subtitle renditions survive while DV supplemental
+        // signaling is removed; sessions without a master remain media-only. Reverts when AirPlay ends.
         if airPlayActive, let lanURL = airPlayPlaybackURL(base: playbackURL) {
             EngineLog.emit("[AirPlay] loadNative serving via \(lanURL.absoluteString)", category: .engine)
             playbackURL = lanURL
@@ -1164,6 +1163,7 @@
         var customPreopened: Demuxer? = nil
         if isCustomSource, let reader = customReader {
             let hint = customFormatHint
+            let probeForDiscImage = customProbeForDiscImage
             do {
                 let isLiveReload = loadedOptions.isLive
                 let discCacheKey = url.absoluteString
@@ -1173,7 +1173,9 @@
                     // selectTitleID rebuilds the disc concat stream for the chosen title (#67).
                     // discCacheKey reuses the disc recognition cached at load so an audio switch on a
                     // remote ISO does not re-parse the UDF directory / playlists (#76).
-                    try d.open(reader: reader, formatHint: hint, profile: reloadProfile, isLive: isLiveReload, selectTitleID: titleToReopen, discCacheKey: discCacheKey)
+                    try d.open(reader: reader, formatHint: hint, profile: reloadProfile,
+                               isLive: isLiveReload, selectTitleID: titleToReopen,
+                               discCacheKey: discCacheKey, probeForDiscImage: probeForDiscImage)
                     return d
                 }.value
             } catch {
@@ -1370,6 +1372,13 @@
             // #112 (audio-switch reanchor): same collapsed-sourceTime slip on the secondary channel.
             selectSecondarySubtitleTrack(index: Int(secondaryEmbeddedToResume), startAt: preSwitchSourceTime)
         }
+        #if os(iOS)
+        // AirPlay replaces the AVPlayerItem during this reload. Re-apply the active native rendition to
+        // the replacement item after the embedded subtitle selection has been restored.
+        if airPlayActive {
+            setNativeSubtitleRendering(true)
+        }
+        #endif
     }
 
     private func elapsedMs(since start: DispatchTime) -> Int {
--- a/Sources/AetherEngine/AetherEngine+Probe.swift
+++ b/Sources/AetherEngine/AetherEngine+Probe.swift
@@ -33,8 +33,12 @@
         case .url(let u):
             try demuxer.open(url: u, extraHeaders: options.httpHeaders)
             displayURL = u
-        case .custom(let reader, let formatHint):
-            try demuxer.open(reader: reader, formatHint: formatHint)
+        case .custom(let reader, let formatHint, let probeForDiscImage):
+            try demuxer.open(
+                reader: reader,
+                formatHint: formatHint,
+                probeForDiscImage: probeForDiscImage
+            )
             displayURL = URL(string: "aether-custom://source")!
         }
         defer { demuxer.close() }
--- a/Sources/AetherEngine/AetherEngine+Subtitles.swift
+++ b/Sources/AetherEngine/AetherEngine+Subtitles.swift
@@ -739,6 +739,7 @@
         }
         let headers = loadedOptions.httpHeaders
         let formatHint = customFormatHint
+        let probeForDiscImage = customProbeForDiscImage
         let w = sourceVideoWidth > 0 ? sourceVideoWidth : 1920
         let h = sourceVideoHeight > 0 ? sourceVideoHeight : 1080
         let startAt = startAtSeconds ?? sourceTime
@@ -752,7 +753,8 @@
                 url: url, reader: reader, formatHint: formatHint, headers: headers,
                 pairs: pairs, startAt: startAt, videoWidth: w, videoHeight: h,
                 callerProbesize: probesize, callerMaxAnalyzeDuration: maxAnalyzeDuration,
-                selectTitleID: titleID, readToEOF: readToEOF
+                selectTitleID: titleID, probeForDiscImage: probeForDiscImage,
+                readToEOF: readToEOF
             )
         }
     }
@@ -811,7 +813,8 @@
         pairs: [(streamIndex: Int32, store: NativeSubtitleCueStore)],
         startAt: Double, videoWidth: Int32, videoHeight: Int32,
         callerProbesize: Int64? = nil, callerMaxAnalyzeDuration: Int64? = nil,
-        selectTitleID: Int? = nil, readToEOF: Bool = false
+        selectTitleID: Int? = nil, probeForDiscImage: Bool = true,
+        readToEOF: Bool = false
     ) async {
         let demuxer = Demuxer()
         let openProfile = DemuxerOpenProfile.subtitleSideDemuxer(
@@ -834,7 +837,9 @@
         }
         do {
             if let reader = reader {
-                try demuxer.open(reader: reader, formatHint: formatHint, profile: openProfile, selectTitleID: selectTitleID, discCacheKey: url.absoluteString)
+                try demuxer.open(reader: reader, formatHint: formatHint, profile: openProfile,
+                                 selectTitleID: selectTitleID, discCacheKey: url.absoluteString,
+                                 probeForDiscImage: probeForDiscImage)
             } else {
                 try demuxer.open(url: url, extraHeaders: headers, profile: openProfile, selectTitleID: selectTitleID)
             }
--- a/Sources/AetherEngine/AetherEngine.swift
+++ b/Sources/AetherEngine/AetherEngine.swift
@@ -599,6 +599,11 @@
     /// Format hint for the active custom source; reused on reload and when opening clones.
     private(set) var customFormatHint: String?
 
+    /// Whether custom-reader reopens should inspect the source as a disc image. Remote ordinary
+    /// media disables this so subtitle, track-switch, and thumbnail side readers do not repeat
+    /// sparse ISO/UDF reads over the network.
+    private(set) var customProbeForDiscImage = true
+
     /// False for forward-only custom sources; reload features (audio switch, background reload) no-op for them.
     private(set) var customSourceIsSeekable = false
 
@@ -1507,11 +1512,13 @@
             isCustomSource = false
             customReader = nil
             customFormatHint = nil
-        case .custom(let reader, let hint):
+            customProbeForDiscImage = true
+        case .custom(let reader, let hint, let probeForDiscImage):
             url = URL(string: "aether-custom://source")!
             isCustomSource = true
             customReader = reader
             customFormatHint = hint
+            customProbeForDiscImage = probeForDiscImage
         }
         loadedURL = url
         loadedOptions = options
@@ -1625,9 +1632,16 @@
                     // isLive configures the AVIOReader for endless-feed mode; must be set at open time because
                     // the probe demuxer is reused as the session demuxer (avformat_open_input runs only once).
                     try probe.open(url: u, extraHeaders: options.httpHeaders, profile: probeProfile, isLive: options.isLive, selectTitleID: discTitleID)
-                case .custom(let reader, let formatHint):
+                case .custom(let reader, let formatHint, let probeForDiscImage):
                     // isLive suppresses SEEK_END duration estimate on forward-only live readers; same open-time requirement.
-                    try probe.open(reader: reader, formatHint: formatHint, profile: probeProfile, isLive: options.isLive, selectTitleID: discTitleID)
+                    try probe.open(
+                        reader: reader,
+                        formatHint: formatHint,
+                        profile: probeProfile,
+                        isLive: options.isLive,
+                        selectTitleID: discTitleID,
+                        probeForDiscImage: probeForDiscImage
+                    )
                 }
             }.value
             probeOpened = true
@@ -2485,8 +2499,8 @@
     }
 
     /// AirPlay (#86, DrHurt): true while the native AVPlayer reports external playback. loadNative reads it to
-    /// serve the loopback over the device's LAN IP (the receiver can't reach 127.0.0.1) AND to force the MEDIA
-    /// playlist (AVPlayer rejects a DV/HDR MASTER playlist on an SDR receiver and won't auto-switch, DrHurt).
+    /// serve the loopback over the device's LAN IP (the receiver can't reach 127.0.0.1) and use either the
+    /// reduced master or the media-only playlist according to what the session produced.
     /// Loopback native path only; a remote-HLS source is already receiver-reachable, so it's left untouched.
     private(set) var airPlayActive = false
     private var externalPlaybackObservation: NSKeyValueObservation?
@@ -2515,9 +2529,9 @@
         guard wantAirPlay != airPlayActive else { return }
         airPlayActive = wantAirPlay
         // Loopback native path only: remote-HLS is already receiver-reachable. Reload so loadNative rebuilds
-        // the playback URL on the LAN IP + media playlist (active) or back on 127.0.0.1 master/media (inactive).
+        // the playback URL on the LAN IP (active) or back on 127.0.0.1 (inactive).
         guard playbackBackend == .native, !loadedOptions.nativeRemoteHLS, loadedURL != nil else { return }
-        EngineLog.emit("[AirPlay] external playback \(wantAirPlay ? "active (wireless) -> LAN media reload" : "ended -> loopback reload")", category: .engine)
+        EngineLog.emit("[AirPlay] external playback \(wantAirPlay ? "active (wireless) -> LAN HLS reload" : "ended -> loopback reload")", category: .engine)
         Task { try? await reloadAtCurrentPosition() }
     }
 
@@ -2534,17 +2548,26 @@
         #endif
     }
 
-    /// AirPlay loopback URL (#86): rewrite the loopback playback URL to the device's LAN IP and force the MEDIA
-    /// playlist, so the receiver reaches the engine-processed stream and isn't handed a DV/HDR master it rejects
-    /// on an SDR panel (DrHurt). nil if no LAN IP (caller keeps the original 127.0.0.1 URL).
+    /// AirPlay loopback URL (#86): rewrite the loopback playback URL to the device's LAN IP. Sessions that
+    /// produced a master use the reduced master, which removes DV supplemental signaling but preserves native
+    /// WebVTT subtitle renditions. Media-only sessions continue to use the media playlist.
     func airPlayPlaybackURL(base: URL) -> URL? {
         guard let lanIP = HLSLocalServer.localActiveIPAddress() else { return nil }
         var c = URLComponents(url: base, resolvingAgainstBaseURL: false)
         c?.host = lanIP
-        c?.path = "/media.m3u8"
+        c?.path = Self.airPlayPlaylistPath(for: base)
         return c?.url
     }
 
+    nonisolated static func airPlayPlaylistPath(for base: URL) -> String {
+        switch base.lastPathComponent.lowercased() {
+        case "master.m3u8", "master_hdr.m3u8":
+            return "/master_hdr.m3u8"
+        default:
+            return "/media.m3u8"
+        }
+    }
+
     #if os(tvOS) || os(iOS)
     /// MPNowPlayingSession for the active AVPlayer audio path, or nil. The host registers transport commands
     /// and writes metadata here to stay the active Now-Playing app across a background pause (tvOS drops a
@@ -2832,6 +2855,7 @@
             customReader?.close()
             customReader = nil
             customFormatHint = nil
+            customProbeForDiscImage = true
             customSourceIsSeekable = false
         }
 
@@ -3146,7 +3170,16 @@
 
 // MARK: - Errors
 
-public enum AetherEngineError: Error {
+public enum AetherEngineError: Error, LocalizedError, Sendable {
     case noVideoStream
     case noAudioStream
+
+    public var errorDescription: String? {
+        switch self {
+        case .noVideoStream:
+            "No video track was found."
+        case .noAudioStream:
+            "No audio track was found."
+        }
+    }
 }
--- a/Sources/AetherEngine/Audio/AudioDecoder.swift
+++ b/Sources/AetherEngine/Audio/AudioDecoder.swift
@@ -406,11 +406,28 @@
     }
 }
 
-enum AudioDecoderError: Error {
+public enum AudioDecoderError: Error, LocalizedError, Sendable {
     case noCodecParameters
     case unsupportedCodec
     case contextAllocationFailed
     case parameterCopyFailed
     case openFailed
     case formatDescriptionFailed
+
+    public var errorDescription: String? {
+        switch self {
+        case .noCodecParameters:
+            "Missing audio codec information."
+        case .unsupportedCodec:
+            "Unsupported audio codec."
+        case .contextAllocationFailed:
+            "Unable to create the audio decoder."
+        case .parameterCopyFailed:
+            "Unable to configure the audio decoder."
+        case .openFailed:
+            "Unable to open the audio decoder."
+        case .formatDescriptionFailed:
+            "Unable to read the audio format."
+        }
+    }
 }
--- a/Sources/AetherEngine/Decoder/VideoDecoderTypes.swift
+++ b/Sources/AetherEngine/Decoder/VideoDecoderTypes.swift
@@ -28,14 +28,14 @@
     func close()
 }
 
-enum VideoDecoderError: Error, LocalizedError {
+public enum VideoDecoderError: Error, LocalizedError, Sendable {
     case noCodecParameters
     case unsupportedCodec(id: UInt32)
     case noExtradata
     case formatDescriptionFailed(status: OSStatus)
     case sessionCreationFailed(status: OSStatus)
 
-    var errorDescription: String? {
+    public var errorDescription: String? {
         switch self {
         case .noCodecParameters: "No codec parameters"
         case .unsupportedCodec(let id): "Unsupported video codec (id: \(id))"
--- a/Sources/AetherEngine/Demuxer/Demuxer.swift
+++ b/Sources/AetherEngine/Demuxer/Demuxer.swift
@@ -314,9 +314,10 @@
     /// no filename is available. `isLive` suppresses SEEK_END that latches EOF
     /// on forward-only readers (38ad60b). AetherEngine#36: DiscReader adapts
     /// DVD/BD ISOs to VOB/MPEGTS concat streams.
-    func open(reader: IOReader, formatHint: String? = nil, profile: DemuxerOpenProfile = .playback, isLive: Bool = false, selectTitleID: Int? = nil, discCacheKey: String? = nil) throws {
+    func open(reader: IOReader, formatHint: String? = nil, profile: DemuxerOpenProfile = .playback, isLive: Bool = false, selectTitleID: Int? = nil, discCacheKey: String? = nil, probeForDiscImage: Bool = true) throws {
         self.openProfile = profile
-        if let discInfo = try DiscReader.wrap(reader, selectTitleID: selectTitleID, cacheKey: discCacheKey) {
+        if probeForDiscImage,
+           let discInfo = try DiscReader.wrap(reader, selectTitleID: selectTitleID, cacheKey: discCacheKey) {
             adoptDiscInfo(discInfo)
             let bridge = CustomIOReaderBridge(reader: discInfo.reader)
             let inputFormat = av_find_input_format(discInfo.formatHint)
@@ -1190,8 +1191,19 @@
     }
 }
 
-enum DemuxerError: Error {
+public enum DemuxerError: Error, LocalizedError, Sendable {
     case openFailed(code: Int32)
     case streamInfoFailed(code: Int32)
     case readFailed(code: Int32)
+
+    public var errorDescription: String? {
+        switch self {
+        case .openFailed(let code):
+            "Unable to open the media container (code \(code))."
+        case .streamInfoFailed(let code):
+            "Unable to read the media tracks (code \(code))."
+        case .readFailed(let code):
+            "Unable to continue reading the media data (code \(code))."
+        }
+    }
 }
--- a/Sources/AetherEngine/FrameExtractor/AetherEngine+FrameExtractor.swift
+++ b/Sources/AetherEngine/FrameExtractor/AetherEngine+FrameExtractor.swift
@@ -59,6 +59,7 @@
             // needs an independent reader; nil (scrub skipped) if the source can't clone.
             guard let clone = customReader?.makeIndependentReader() else { return nil }
             return FrameExtractor(reader: clone, formatHint: customFormatHint,
+                                  probeForDiscImage: customProbeForDiscImage,
                                   yieldWhile: sessionYieldSignal())
         }
         guard let url = loadedURL else { return nil }
--- a/Sources/AetherEngine/FrameExtractor/FrameDecodeContext.swift
+++ b/Sources/AetherEngine/FrameExtractor/FrameDecodeContext.swift
@@ -18,6 +18,7 @@
     /// idle-reopen path can rebuild over the still-alive reader).
     private let reader: IOReader?
     private let formatHint: String?
+    private let probeForDiscImage: Bool
     /// For a disc image (Blu-ray / DVD ISO) URL, the title to extract stills from. nil = the default
     /// (main) title. Threaded into `Demuxer.open` so a still follows the currently-selected disc title
     /// instead of always decoding the default one (AE#105).
@@ -101,15 +102,17 @@
         self.httpHeaders = httpHeaders
         self.reader = nil
         self.formatHint = nil
+        self.probeForDiscImage = true
         self.selectTitleID = selectTitleID
     }
 
-    init(reader: IOReader, formatHint: String?) {
+    init(reader: IOReader, formatHint: String?, probeForDiscImage: Bool) {
         // Placeholder; unused when reader != nil (openInternal opens the reader).
         self.url = URL(string: "aether-custom://frame-extractor")!
         self.httpHeaders = [:]
         self.reader = reader
         self.formatHint = formatHint
+        self.probeForDiscImage = probeForDiscImage
         self.selectTitleID = nil
     }
 
@@ -151,7 +154,8 @@
     private func openInternal() throws {
         let demuxer = Demuxer()
         if let reader = reader {
-            try demuxer.open(reader: reader, formatHint: formatHint, profile: .stillExtraction)
+            try demuxer.open(reader: reader, formatHint: formatHint, profile: .stillExtraction,
+                             probeForDiscImage: probeForDiscImage)
         } else {
             try demuxer.open(url: url, extraHeaders: httpHeaders, profile: .stillExtraction, selectTitleID: selectTitleID)
         }
--- a/Sources/AetherEngine/FrameExtractor/FrameExtractor.swift
+++ b/Sources/AetherEngine/FrameExtractor/FrameExtractor.swift
@@ -62,8 +62,10 @@
     /// Construct over a custom `IOReader` source (a clone with its own cursor).
     /// The extractor owns the reader and closes it on teardown.
     public init(reader: IOReader, formatHint: String? = nil,
+                probeForDiscImage: Bool = true,
                 yieldWhile: (@Sendable () -> Bool)? = nil) {
-        self.init(context: FrameDecodeContext(reader: reader, formatHint: formatHint),
+        self.init(context: FrameDecodeContext(reader: reader, formatHint: formatHint,
+                                              probeForDiscImage: probeForDiscImage),
                   yieldWhile: yieldWhile)
     }
 
--- a/Sources/AetherEngine/IO/IOReader.swift
+++ b/Sources/AetherEngine/IO/IOReader.swift
@@ -26,5 +26,12 @@
 public enum MediaSource: Sendable {
     case url(URL)
     /// `formatHint`: optional container short name ("mp4", "matroska", "mpegts") to disambiguate probing when no filename is present; nil probes from content.
-    case custom(IOReader, formatHint: String? = nil)
+    /// `probeForDiscImage`: keep enabled for raw ISO/UDF sources. Disable it when the caller already
+    /// knows the custom reader represents an ordinary media file, avoiding remote random reads used
+    /// solely to sniff ISO 9660/UDF signatures before the supplied container hint is applied.
+    case custom(
+        IOReader,
+        formatHint: String? = nil,
+        probeForDiscImage: Bool = true
+    )
 }
--- a/Tests/AetherEngineTests/AirPlayPlaylistRoutingTests.swift
+++ b/Tests/AetherEngineTests/AirPlayPlaylistRoutingTests.swift
@@ -0,0 +1,18 @@
+import Foundation
+import Testing
+@testable import AetherEngine
+
+@Suite("AirPlay playlist routing")
+struct AirPlayPlaylistRoutingTests {
+    @Test("Master playlists retain subtitle renditions")
+    func masterUsesReducedMaster() {
+        let base = URL(string: "http://127.0.0.1:1234/master.m3u8")!
+        #expect(AetherEngine.airPlayPlaylistPath(for: base) == "/master_hdr.m3u8")
+    }
+
+    @Test("Media-only sessions remain media-only")
+    func mediaStaysMedia() {
+        let base = URL(string: "http://127.0.0.1:1234/media.m3u8")!
+        #expect(AetherEngine.airPlayPlaylistPath(for: base) == "/media.m3u8")
+    }
+}
--- a/Tests/AetherEngineTests/CustomDiscProbePolicyTests.swift
+++ b/Tests/AetherEngineTests/CustomDiscProbePolicyTests.swift
@@ -0,0 +1,58 @@
+import XCTest
+@testable import AetherEngine
+
+final class CustomDiscProbePolicyTests: XCTestCase {
+    func testDisabledDiscProbeSkipsISOAndUDFSignatureOffsets() {
+        let reader = TrackingIOReader()
+        let demuxer = Demuxer()
+
+        XCTAssertThrowsError(
+            try demuxer.open(
+                reader: reader,
+                formatHint: "matroska",
+                probeForDiscImage: false
+            )
+        )
+
+        XCTAssertFalse(reader.seekOffsets.contains(0x8001))
+        XCTAssertFalse(reader.seekOffsets.contains(256 * 2048))
+    }
+
+    func testDefaultDiscProbeChecksISOAndUDFSignatureOffsets() {
+        let reader = TrackingIOReader()
+        let demuxer = Demuxer()
+
+        XCTAssertThrowsError(
+            try demuxer.open(reader: reader, formatHint: "matroska")
+        )
+
+        XCTAssertTrue(reader.seekOffsets.contains(0x8001))
+        XCTAssertTrue(reader.seekOffsets.contains(256 * 2048))
+    }
+}
+
+private final class TrackingIOReader: IOReader, @unchecked Sendable {
+    private let lock = NSLock()
+    private var offset: Int64 = 0
+    private(set) var seekOffsets: [Int64] = []
+
+    func read(_ buffer: UnsafeMutablePointer<UInt8>?, size: Int32) -> Int32 {
+        guard let buffer, size > 0 else { return 0 }
+        let count = min(Int(size), 4096)
+        buffer.initialize(repeating: 0, count: count)
+        lock.withLock { offset += Int64(count) }
+        return Int32(count)
+    }
+
+    func seek(offset requestedOffset: Int64, whence: Int32) -> Int64 {
+        lock.withLock {
+            if whence & 0x10000 != 0 { return 4096 }
+            guard whence & ~0x20000 == SEEK_SET else { return -1 }
+            offset = requestedOffset
+            seekOffsets.append(requestedOffset)
+            return requestedOffset
+        }
+    }
+
+    func close() {}
+}
