HaishinKit.swift/Sources/MPEG/TSField.swift

202 lines
7.1 KiB
Swift

import Foundation
class TSAdaptationField {
static let PCRSize: Int = 6
static let fixedSectionSize: Int = 2
var length: UInt8 = 0
var discontinuityIndicator = false
var randomAccessIndicator = false
var elementaryStreamPriorityIndicator = false
var PCRFlag = false
var OPCRFlag = false
var splicingPointFlag = false
var transportPrivateDataFlag = false
var adaptationFieldExtensionFlag = false
var PCR = Data()
var OPCR = Data()
var spliceCountdown: UInt8 = 0
var transportPrivateDataLength: UInt8 = 0
var transportPrivateData = Data()
var adaptationExtension: TSAdaptationExtensionField?
var stuffingBytes = Data()
init() {
}
init?(data: Data) {
self.data = data
}
func compute() {
length = UInt8(truncatingIfNeeded: TSAdaptationField.fixedSectionSize)
length += UInt8(truncatingIfNeeded: PCR.count)
length += UInt8(truncatingIfNeeded: OPCR.count)
length += UInt8(truncatingIfNeeded: transportPrivateData.count)
if let adaptationExtension: TSAdaptationExtensionField = adaptationExtension {
length += adaptationExtension.length + 1
}
length += UInt8(truncatingIfNeeded: stuffingBytes.count)
length -= 1
}
func stuffing(_ size: Int) {
stuffingBytes = Data(repeating: 0xff, count: size)
length += UInt8(size)
}
}
extension TSAdaptationField: DataConvertible {
// MARK: DataConvertible
var data: Data {
get {
var byte: UInt8 = 0
byte |= discontinuityIndicator ? 0x80 : 0
byte |= randomAccessIndicator ? 0x40 : 0
byte |= elementaryStreamPriorityIndicator ? 0x20 : 0
byte |= PCRFlag ? 0x10 : 0
byte |= OPCRFlag ? 0x08 : 0
byte |= splicingPointFlag ? 0x04 : 0
byte |= transportPrivateDataFlag ? 0x02 : 0
byte |= adaptationFieldExtensionFlag ? 0x01 : 0
let buffer = ByteArray()
.writeUInt8(length)
.writeUInt8(byte)
if PCRFlag {
buffer.writeBytes(PCR)
}
if OPCRFlag {
buffer.writeBytes(OPCR)
}
if splicingPointFlag {
buffer.writeUInt8(spliceCountdown)
}
if transportPrivateDataFlag {
buffer.writeUInt8(transportPrivateDataLength).writeBytes(transportPrivateData)
}
if adaptationFieldExtensionFlag {
buffer.writeBytes(adaptationExtension!.data)
}
return buffer.writeBytes(stuffingBytes).data
}
set {
let buffer = ByteArray(data: newValue)
do {
length = try buffer.readUInt8()
let byte: UInt8 = try buffer.readUInt8()
discontinuityIndicator = (byte & 0x80) == 0x80
randomAccessIndicator = (byte & 0x40) == 0x40
elementaryStreamPriorityIndicator = (byte & 0x20) == 0x20
PCRFlag = (byte & 0x10) == 0x10
OPCRFlag = (byte & 0x08) == 0x08
splicingPointFlag = (byte & 0x04) == 0x04
transportPrivateDataFlag = (byte & 0x02) == 0x02
adaptationFieldExtensionFlag = (byte & 0x01) == 0x01
if PCRFlag {
PCR = try buffer.readBytes(TSAdaptationField.PCRSize)
}
if OPCRFlag {
OPCR = try buffer.readBytes(TSAdaptationField.PCRSize)
}
if splicingPointFlag {
spliceCountdown = try buffer.readUInt8()
}
if transportPrivateDataFlag {
transportPrivateDataLength = try buffer.readUInt8()
transportPrivateData = try buffer.readBytes(Int(transportPrivateDataLength))
}
if adaptationFieldExtensionFlag {
let length = Int(try buffer.readUInt8())
buffer.position -= 1
adaptationExtension = TSAdaptationExtensionField(data: try buffer.readBytes(length + 1))
}
stuffingBytes = try buffer.readBytes(buffer.bytesAvailable)
} catch {
logger.error("\(buffer)")
}
}
}
}
extension TSAdaptationField: CustomDebugStringConvertible {
// MARK: CustomDebugStringConvertible
var debugDescription: String {
Mirror(reflecting: self).debugDescription
}
}
struct TSAdaptationExtensionField {
var length: UInt8 = 0
var legalTimeWindowFlag = false
var piecewiseRateFlag = false
var seamlessSpiceFlag = false
var legalTimeWindowOffset: UInt16 = 0
var piecewiseRate: UInt32 = 0
var spliceType: UInt8 = 0
var DTSNextAccessUnit = Data(count: 5)
init?(data: Data) {
self.data = data
}
}
extension TSAdaptationExtensionField: DataConvertible {
// MARK: DataConvertible
var data: Data {
get {
let buffer = ByteArray()
.writeUInt8(length)
.writeUInt8(
(legalTimeWindowFlag ? 0x80 : 0) |
(piecewiseRateFlag ? 0x40 : 0) |
(seamlessSpiceFlag ? 0x1f : 0)
)
if legalTimeWindowFlag {
buffer.writeUInt16((legalTimeWindowFlag ? 0x8000 : 0) | legalTimeWindowOffset)
}
if piecewiseRateFlag {
buffer.writeUInt24(piecewiseRate)
}
if seamlessSpiceFlag {
buffer
.writeUInt8(spliceType)
.writeUInt8(spliceType << 4 | DTSNextAccessUnit[0])
.writeBytes(DTSNextAccessUnit.subdata(in: 1..<DTSNextAccessUnit.count))
}
return buffer.data
}
set {
let buffer = ByteArray(data: newValue)
do {
var byte: UInt8 = 0
length = try buffer.readUInt8()
byte = try buffer.readUInt8()
legalTimeWindowFlag = (byte & 0x80) == 0x80
piecewiseRateFlag = (byte & 0x40) == 0x40
seamlessSpiceFlag = (byte & 0x1f) == 0x1f
if legalTimeWindowFlag {
legalTimeWindowOffset = try buffer.readUInt16()
legalTimeWindowFlag = (legalTimeWindowOffset & 0x8000) == 0x8000
}
if piecewiseRateFlag {
piecewiseRate = try buffer.readUInt24()
}
if seamlessSpiceFlag {
DTSNextAccessUnit = try buffer.readBytes(DTSNextAccessUnit.count)
spliceType = DTSNextAccessUnit[0] & 0xf0 >> 4
DTSNextAccessUnit[0] = DTSNextAccessUnit[0] & 0x0f
}
} catch {
logger.error("\(buffer)")
}
}
}
}
extension TSAdaptationExtensionField: CustomDebugStringConvertible {
// MARK: CustomDebugStringConvertible
var debugDescription: String {
Mirror(reflecting: self).debugDescription
}
}