Skip to content
This repository has been archived by the owner on Jul 8, 2024. It is now read-only.

Haishinkit changes to keep code up to date #1

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/HTTP/HTTPStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ open class HTTPStream: NetStream {

/// The name of stream.
private(set) var name: String?
private lazy var tsWriter = TSFileWriter()
public lazy var tsWriter = TSFileWriter()

open func publish(_ name: String?) {
lockQueue.async {
Expand Down
30 changes: 21 additions & 9 deletions Sources/HTTP/M3U.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,38 @@ import Foundation
/**
- seealso: https://tools.ietf.org/html/draft-pantos-http-live-streaming-19
*/
struct M3U {
static let header: String = "#EXTM3U"
static let defaultVersion: Int = 3

public struct M3U {
public static let header: String = "#EXTM3U"
public static let defaultVersion: Int = 3
var version: Int = M3U.defaultVersion
var mediaList: [M3UMediaInfo] = []
var mediaSequence: Int = 0
var targetDuration: Double = 5
public var mediaSequence: Int = 0
public var targetDuration: Double = 5
public init() {

}
}

extension M3U: CustomStringConvertible {
// MARK: CustomStringConvertible
var description: String {
public var description: String {
var lines: [String] = [
"#EXTM3U",
"#EXT-X-VERSION:\(version)",
"#EXT-X-MEDIA-SEQUENCE:\(mediaSequence)",
"#EXT-X-TARGETDURATION:\(Int(targetDuration))"
]
for info in mediaList {
lines.append("#EXTINF:\(info.duration),")
lines.append(info.url.pathComponents.last!)
if info.isSkipped ?? false {
continue
}
if info.isDiscontinuous {
lines.append("#EXT-X-DISCONTINUITY")
}
lines.append("#EXTINF:\(info.duration),")
lines.append(info.url.pathComponents.last!)

}
return lines.joined(separator: "\r\n")
}
Expand All @@ -34,4 +44,6 @@ extension M3U: CustomStringConvertible {
struct M3UMediaInfo {
let url: URL
let duration: Double
var isDiscontinuous: Bool
var isSkipped: Bool?
}
97 changes: 80 additions & 17 deletions Sources/MPEG/TSWriter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import SwiftPMSupport
public protocol TSWriterDelegate: AnyObject {
func writer(_ writer: TSWriter, didRotateFileHandle timestamp: CMTime)
func writer(_ writer: TSWriter, didOutput data: Data)
func didGenerateTS(_ file: URL)
func didGenerateM3U8(_ file: URL)
}

public extension TSWriterDelegate {
Expand All @@ -33,7 +35,11 @@ public class TSWriter: Running {
/// This instance is running to process(true) or not(false).
public internal(set) var isRunning: Atomic<Bool> = .init(false)
/// The exptected medias = [.video, .audio].
public var expectedMedias: Set<AVMediaType> = []
public var expectedMedias: Set<AVMediaType> = [] {
didSet {
print("expected medias \(expectedMedias.count)")
}
}

var audioContinuityCounter: UInt8 = 0
var videoContinuityCounter: UInt8 = 0
Expand Down Expand Up @@ -295,15 +301,19 @@ extension TSWriter: VideoCodecDelegate {
}
}

class TSFileWriter: TSWriter {
static let defaultSegmentCount: Int = 3
static let defaultSegmentMaxCount: Int = 12
public class TSFileWriter: TSWriter {
static let defaultSegmentCount: Int = 10000
static let defaultSegmentMaxCount: Int = 10000
public var baseFolder: URL?
public var shouldAppendToStream: Bool = false

var segmentMaxCount: Int = TSFileWriter.defaultSegmentMaxCount
private(set) var files: [M3UMediaInfo] = []
private var currentFileHandle: FileHandle?
private var currentFileURL: URL?
private var sequence: Int = 0
public var isDiscontinuity = false
private var isTerminating: Bool = false

var playlist: String {
var m3u8 = M3U()
Expand Down Expand Up @@ -331,7 +341,11 @@ class TSFileWriter: TSWriter {
return
}
let fileManager = FileManager.default

guard let base = baseFolder else {

return
}

#if os(OSX)
let bundleIdentifier: String? = Bundle.main.bundleIdentifier
let temp: String = bundleIdentifier == nil ? NSTemporaryDirectory() : NSTemporaryDirectory() + bundleIdentifier! + "/"
Expand All @@ -347,13 +361,31 @@ class TSFileWriter: TSWriter {
}
}

let filename: String = Int(timestamp.seconds).description + ".ts"
let url = URL(fileURLWithPath: temp + filename)

if let currentFileURL: URL = currentFileURL {
files.append(M3UMediaInfo(url: currentFileURL, duration: duration))
// let filename: String = Int(timestamp.seconds).description + ".ts"
let playlistUrl = base.appendingPathComponent("ScreenRecording.m3u8")
let filename = String(format: "part%.5i.ts", sequence)
let url = base.appendingPathComponent(filename)

if isTerminating { return }

// Toss part0 due to bad duration calculation.
// shouldAppendToStream is true when countdown-completed arrives
if let currentUrl = currentFileURL, sequence > 1 && shouldAppendToStream {
// let asset = AVAsset(url: currentUrl)
// let calculatedDuration = CMTimeGetSeconds(asset.duration)
// Logger.info("Duration: \(duration) Calculated duration: \(calculatedDuration)")
files.append(M3UMediaInfo(url: currentUrl, duration: duration, isDiscontinuous: isDiscontinuity))
isDiscontinuity = false
fileManager.createFile(atPath: playlistUrl.path, contents: playlist.data(using: .utf8), attributes: nil)
notifyDelegate(tsUrl: currentUrl, playlistUrl: playlistUrl)
}

sequence += 1
}
if shouldAppendToStream {
segmentDuration = 2
} else {
segmentDuration = 1
}

fileManager.createFile(atPath: url.path, contents: nil, attributes: nil)
if TSFileWriter.defaultSegmentMaxCount <= files.count {
Expand All @@ -380,7 +412,31 @@ class TSFileWriter: TSWriter {
writeProgram()
rotatedTimestamp = timestamp
}



func notifyDelegate(tsUrl: URL, playlistUrl: URL) {
self.delegate?.didGenerateTS(tsUrl)
self.delegate?.didGenerateM3U8(playlistUrl)
}

private func writeFinal() {
guard let base = baseFolder else {
return
}
DispatchQueue.main.asyncAfter(deadline: .now()+(TSWriter.defaultSegmentDuration+1)) {
if let currentUrl = self.currentFileURL {
let playlistUrl = base.appendingPathComponent("ScreenRecording.m3u8")

self.files.append(M3UMediaInfo(url: currentUrl, duration: TSWriter.defaultSegmentDuration, isDiscontinuous: false))
FileManager.default.createFile(atPath: playlistUrl.path, contents: self.playlist.data(using: .utf8), attributes: nil)
self.notifyDelegate(tsUrl: currentUrl, playlistUrl: playlistUrl)
}
self.currentFileURL = nil
self.currentFileHandle = nil
super.stopRunning()
}
}

override func write(_ data: Data) {
nstry({
self.currentFileHandle?.write(data)
Expand All @@ -391,14 +447,21 @@ class TSFileWriter: TSWriter {
super.write(data)
}

override func stopRunning() {
public override func stopRunning() {
guard !isRunning.value else {
return
}
currentFileURL = nil
currentFileHandle = nil
removeFiles()
super.stopRunning()
nstry({
self.currentFileHandle?.synchronizeFile()
}, { exeption in
// Logger.warn("\(exeption)")

})

currentFileHandle?.closeFile()

writeFinal()

}

func getFilePath(_ fileName: String) -> String? {
Expand Down
4 changes: 3 additions & 1 deletion Sources/Media/IOMixer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import SwiftPMSupport
import UIKit
#endif
#if os(iOS) || os(macOS)
extension AVCaptureSession.Preset {
public extension AVCaptureSession.Preset {
static let `default`: AVCaptureSession.Preset = .hd1280x720
}
#endif
Expand Down Expand Up @@ -215,6 +215,8 @@ public class IOMixer {
func useSampleBuffer(sampleBuffer: CMSampleBuffer, mediaType: AVMediaType) -> Bool {
switch mediaSync {
case .video:
print(videoTimeStamp.seconds)
print(sampleBuffer.presentationTimeStamp.seconds)
if mediaType == .audio {
return !videoTimeStamp.seconds.isZero && videoTimeStamp.seconds <= sampleBuffer.presentationTimeStamp.seconds
}
Expand Down
6 changes: 5 additions & 1 deletion Sources/Media/IOVideoUnit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,11 @@ extension IOVideoUnit: AVCaptureVideoDataOutputSampleBufferDelegate {
}
appendSampleBuffer(sampleBuffer)
} else if multiCamCapture.output == captureOutput {
multiCamSampleBuffer = sampleBuffer
// multiCamSampleBuffer = sampleBuffer
guard mixer?.useSampleBuffer(sampleBuffer: sampleBuffer, mediaType: AVMediaType.video) == true else {
return
}
appendSampleBuffer(sampleBuffer)
}
}
}
Expand Down