Skip to content

Commit

Permalink
Implement MKV as a Protocol and refractor
Browse files Browse the repository at this point in the history
Signed-off-by: Ethan Dye <[email protected]>
  • Loading branch information
ecdye committed Sep 20, 2024
1 parent 262f4ef commit b97a054
Show file tree
Hide file tree
Showing 8 changed files with 393 additions and 553 deletions.
5 changes: 0 additions & 5 deletions Sources/macSubtitleOCR/MKV/EBML/EBMLParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,13 @@ func readVINT(from fileHandle: FileHandle, unmodified: Bool = false) -> UInt64 {
}

// Extract the value
logger.debug("Length: \(length), Mask: 0x\(String(format: "%08X", mask))")
logger.debug("Length: \(length), Mask - 1: 0x\(String(format: "%08X", mask - 1))")
if mask - 1 == 0x0F {
mask = 0xFF // Hacky workaround that I still don't understand why is needed
} else if length == 1, !unmodified {
mask = firstByte
} else {
mask = mask - 1
}
logger.debug("Byte before: 0x\(String(format: "%08X", firstByte))")
logger.debug("Byte after: 0x\(String(format: "%08X", firstByte & mask))")

var value = UInt64(firstByte & mask)

Expand All @@ -61,6 +57,5 @@ func readBytes(from fileHandle: FileHandle, length: Int) -> Data? {
func readEBMLElement(from fileHandle: FileHandle, unmodified: Bool = false) -> (elementID: UInt32, elementSize: UInt64) {
let elementID = readVINT(from: fileHandle, unmodified: unmodified)
let elementSize = readVINT(from: fileHandle, unmodified: true)
logger.debug("elementID: 0x\(String(format: "%08X", elementID)), elementSize: \(elementSize)")
return (UInt32(elementID), elementSize)
}
287 changes: 0 additions & 287 deletions Sources/macSubtitleOCR/MKV/MKV.swift

This file was deleted.

80 changes: 80 additions & 0 deletions Sources/macSubtitleOCR/MKV/MKVFileHandler.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import Foundation
import os

class MKVFileHandler: MKVFileHandling {
var fileHandle: FileHandle
var eof: UInt64
var timestampScale: Double = 1000000.0 // Default value if not specified in a given MKV file
var logger = Logger(subsystem: "github.ecdye.macSubtitleOCR", category: "mkv")

init(filePath: String) throws {
guard FileManager.default.fileExists(atPath: filePath) else {
throw macSubtitleOCRError.fileReadError
}
self.fileHandle = try FileHandle(forReadingFrom: URL(fileURLWithPath: filePath))

Check warning on line 14 in Sources/macSubtitleOCR/MKV/MKVFileHandler.swift

View workflow job for this annotation

GitHub Actions / Lint

Insert/remove explicit self where applicable. (redundantSelf)

Check warning on line 14 in Sources/macSubtitleOCR/MKV/MKVFileHandler.swift

View workflow job for this annotation

GitHub Actions / Lint

Insert/remove explicit self where applicable. (redundantSelf)
self.eof = fileHandle.seekToEndOfFile()

Check warning on line 15 in Sources/macSubtitleOCR/MKV/MKVFileHandler.swift

View workflow job for this annotation

GitHub Actions / Lint

Insert/remove explicit self where applicable. (redundantSelf)

Check warning on line 15 in Sources/macSubtitleOCR/MKV/MKVFileHandler.swift

View workflow job for this annotation

GitHub Actions / Lint

Insert/remove explicit self where applicable. (redundantSelf)
fileHandle.seek(toFileOffset: 0)
}

deinit {
fileHandle.closeFile()
}

func locateSegment() -> UInt64? {
if let (segmentSize, _) = findElement(withID: EBML.segmentID, avoidCluster: true) as? (UInt64, UInt32) {
return segmentSize
}
return nil
}

func locateCluster() -> UInt64? {
if let (clusterSize, _) = findElement(withID: EBML.cluster, avoidCluster: false) as? (UInt64, UInt32) {
return clusterSize
}
return nil
}

// Find EBML element by ID, avoiding Cluster header
func findElement(withID targetID: UInt32, _ tgtID2: UInt32? = nil, avoidCluster: Bool = true) -> (UInt64?, UInt32?) {
while let (elementID, elementSize, elementOffset) = tryParseElement() {
// Ensure we stop if we have reached or passed the EOF
if fileHandle.offsetInFile >= eof {
return (nil, nil)
}

// If, by chance, we find a TimestampScale element, update it from the default
if elementID == EBML.timestampScale {
timestampScale = Double(readFixedLengthNumber(
fileHandle: fileHandle,
length: Int(elementSize)))
// swiftformat:disable:next redundantSelf
logger.debug("Found timestamp scale: \(self.timestampScale)")
return (nil, nil)
}

// If a Cluster header is encountered, seek back to the start of the Cluster
if elementID == EBML.cluster && avoidCluster {
logger.debug("Encountered Cluster: seeking back to before the cluster header")
fileHandle.seek(toFileOffset: elementOffset)
return (nil, nil)
}

// If the element matches the target ID (or secondary ID), return its size
if elementID == targetID || (tgtID2 != nil && elementID == tgtID2!) {
return (elementSize, elementID)
} else {
// Skip over the element's data by seeking to its end
logger.debug("Found: \(elementID), but not \(targetID), skipping element")
fileHandle.seek(toFileOffset: fileHandle.offsetInFile + elementSize)
}
}

return (nil, nil)
}

func tryParseElement() -> (elementID: UInt32, elementSize: UInt64, oldOffset: UInt64)? {
let oldOffset = fileHandle.offsetInFile
let (elementID, elementSize) = readEBMLElement(from: fileHandle)
return (elementID, elementSize, oldOffset: oldOffset)
}
}
Loading

0 comments on commit b97a054

Please sign in to comment.