106 lines
3.2 KiB
Swift
106 lines
3.2 KiB
Swift
import Foundation
|
|
|
|
protocol TSReaderDelegate: class {
|
|
func didReadPacketizedElementaryStream(_ data:ElementaryStreamSpecificData, PES:PacketizedElementaryStream)
|
|
}
|
|
|
|
// MARK: -
|
|
class TSReader {
|
|
weak var delegate:TSReaderDelegate?
|
|
|
|
private(set) var PAT:ProgramAssociationSpecific? {
|
|
didSet {
|
|
guard let PAT:ProgramAssociationSpecific = PAT else {
|
|
return
|
|
}
|
|
for (channel, PID) in PAT.programs {
|
|
dictionaryForPrograms[PID] = channel
|
|
}
|
|
}
|
|
}
|
|
private(set) var PMT:[UInt16: ProgramMapSpecific] = [:] {
|
|
didSet {
|
|
for (_, pmt) in PMT {
|
|
for data in pmt.elementaryStreamSpecificData {
|
|
dictionaryForESSpecData[data.elementaryPID] = data
|
|
}
|
|
}
|
|
}
|
|
}
|
|
private(set) var numberOfPackets:Int = 0
|
|
|
|
private var eof:UInt64 = 0
|
|
private var cursor:Int = 0
|
|
private var fileHandle:FileHandle?
|
|
private var dictionaryForPrograms:[UInt16:UInt16] = [:]
|
|
private var dictionaryForESSpecData:[UInt16:ElementaryStreamSpecificData] = [:]
|
|
private var packetizedElementaryStreams:[UInt16:PacketizedElementaryStream] = [:]
|
|
|
|
init(url:URL) throws {
|
|
fileHandle = try FileHandle(forReadingFrom: url)
|
|
eof = fileHandle!.seekToEndOfFile()
|
|
}
|
|
|
|
func read() {
|
|
while (hasNext()) {
|
|
guard let packet:TSPacket = next() else {
|
|
continue
|
|
}
|
|
numberOfPackets += 1
|
|
if (packet.PID == 0x0000) {
|
|
PAT = ProgramAssociationSpecific(packet.payload)
|
|
continue
|
|
}
|
|
if let channel:UInt16 = dictionaryForPrograms[packet.PID] {
|
|
PMT[channel] = ProgramMapSpecific(packet.payload)
|
|
continue
|
|
}
|
|
if let data:ElementaryStreamSpecificData = dictionaryForESSpecData[packet.PID] {
|
|
readPacketizedElementaryStream(data, packet: packet)
|
|
}
|
|
}
|
|
}
|
|
|
|
func readPacketizedElementaryStream(_ data:ElementaryStreamSpecificData, packet: TSPacket) {
|
|
if (packet.payloadUnitStartIndicator) {
|
|
if let PES:PacketizedElementaryStream = packetizedElementaryStreams[packet.PID] {
|
|
delegate?.didReadPacketizedElementaryStream(data, PES: PES)
|
|
}
|
|
packetizedElementaryStreams[packet.PID] = PacketizedElementaryStream(packet.payload)
|
|
return
|
|
}
|
|
let _:Int? = packetizedElementaryStreams[packet.PID]?.append(packet.payload)
|
|
}
|
|
|
|
func close() {
|
|
fileHandle?.closeFile()
|
|
}
|
|
}
|
|
|
|
extension TSReader: Iterator {
|
|
// MARK: Iterator
|
|
typealias T = TSPacket
|
|
|
|
func next() -> TSPacket? {
|
|
guard let fileHandle = fileHandle else {
|
|
return nil
|
|
}
|
|
defer {
|
|
cursor += 1
|
|
}
|
|
fileHandle.seek(toFileOffset: UInt64(cursor * TSPacket.size))
|
|
return TSPacket(data: fileHandle.readData(ofLength: TSPacket.size))
|
|
}
|
|
|
|
func hasNext() -> Bool {
|
|
return UInt64(cursor * TSPacket.size) < eof
|
|
}
|
|
}
|
|
|
|
extension TSReader: CustomStringConvertible {
|
|
// MARK: CustomStringConvertible
|
|
var description:String {
|
|
return Mirror(reflecting: self).description
|
|
}
|
|
}
|