BrashUp Replay Kit Live #81
This commit is contained in:
parent
7eacded159
commit
bc708b6dae
|
@ -30,9 +30,9 @@
|
||||||
<key>NSExtensionPointIdentifier</key>
|
<key>NSExtensionPointIdentifier</key>
|
||||||
<string>com.apple.broadcast-services</string>
|
<string>com.apple.broadcast-services</string>
|
||||||
<key>NSExtensionPrincipalClass</key>
|
<key>NSExtensionPrincipalClass</key>
|
||||||
<string>$(PRODUCT_MODULE_NAME).SampleHandler</string>
|
<string>$(PRODUCT_MODULE_NAME).MovieClipHandler</string>
|
||||||
<key>RPBroadcastProcessMode</key>
|
<key>RPBroadcastProcessMode</key>
|
||||||
<string>RPBroadcastProcessModeSampleBuffer</string>
|
<string>RPBroadcastProcessModeMP4Clip</string>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import lf
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class MovieClipHandler: RTMPMP4ClipHandler {
|
||||||
|
}
|
|
@ -22,6 +22,10 @@ class BroadcastViewController: UIViewController {
|
||||||
]
|
]
|
||||||
|
|
||||||
let broadcastConfiguration:RPBroadcastConfiguration = RPBroadcastConfiguration()
|
let broadcastConfiguration:RPBroadcastConfiguration = RPBroadcastConfiguration()
|
||||||
|
broadcastConfiguration.clipDuration = 2
|
||||||
|
broadcastConfiguration.videoCompressionProperties = [
|
||||||
|
AVVideoProfileLevelKey: AVVideoProfileLevelH264BaselineAutoLevel as NSSecureCoding & NSObjectProtocol,
|
||||||
|
]
|
||||||
|
|
||||||
self.extensionContext?.completeRequest(
|
self.extensionContext?.completeRequest(
|
||||||
withBroadcast: broadcastURL,
|
withBroadcast: broadcastURL,
|
||||||
|
|
|
@ -158,12 +158,14 @@ final class LiveViewController: NSViewController {
|
||||||
httpStream.attach(camera: nil)
|
httpStream.attach(camera: nil)
|
||||||
rtmpStream.attach(audio: DeviceUtil.device(withLocalizedName: audioPopUpButton.itemTitles[audioPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeAudio))
|
rtmpStream.attach(audio: DeviceUtil.device(withLocalizedName: audioPopUpButton.itemTitles[audioPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeAudio))
|
||||||
rtmpStream.attach(camera: DeviceUtil.device(withLocalizedName: cameraPopUpButton.itemTitles[cameraPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeVideo))
|
rtmpStream.attach(camera: DeviceUtil.device(withLocalizedName: cameraPopUpButton.itemTitles[cameraPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeVideo))
|
||||||
|
lfView.attach(stream: rtmpStream)
|
||||||
urlField.stringValue = LiveViewController.defaultURL
|
urlField.stringValue = LiveViewController.defaultURL
|
||||||
case 1:
|
case 1:
|
||||||
rtmpStream.attach(audio: nil)
|
rtmpStream.attach(audio: nil)
|
||||||
rtmpStream.attach(camera: nil)
|
rtmpStream.attach(camera: nil)
|
||||||
httpStream.attach(audio: DeviceUtil.device(withLocalizedName: audioPopUpButton.itemTitles[audioPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeAudio))
|
httpStream.attach(audio: DeviceUtil.device(withLocalizedName: audioPopUpButton.itemTitles[audioPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeAudio))
|
||||||
httpStream.attach(camera: DeviceUtil.device(withLocalizedName: cameraPopUpButton.itemTitles[cameraPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeVideo))
|
httpStream.attach(camera: DeviceUtil.device(withLocalizedName: cameraPopUpButton.itemTitles[cameraPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeVideo))
|
||||||
|
lfView.attach(stream: httpStream)
|
||||||
urlField.stringValue = "http://{ipAddress}:8080/hello/playlist.m3u8"
|
urlField.stringValue = "http://{ipAddress}:8080/hello/playlist.m3u8"
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
|
|
@ -3,22 +3,41 @@ import Foundation
|
||||||
|
|
||||||
@available(iOS 10.0, *)
|
@available(iOS 10.0, *)
|
||||||
public class RTMPBroadcaster: RTMPConnection {
|
public class RTMPBroadcaster: RTMPConnection {
|
||||||
private var stream:RTMPStream?
|
static let `default`:RTMPBroadcaster = RTMPBroadcaster()
|
||||||
|
|
||||||
func process(sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
|
private var stream:RTMPStream!
|
||||||
guard let stream:RTMPStream = stream, stream.readyState == .publishing else {
|
private var connecting:Bool = false
|
||||||
|
private let lockQueue:DispatchQueue = DispatchQueue(label: "com.github.shogo4405.lf.RTMPBroadcaster.lock")
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
super.init()
|
||||||
|
stream = RTMPStream(connection: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func connect(_ command: String, arguments: Any?...) {
|
||||||
|
lockQueue.sync {
|
||||||
|
if (connecting) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch sampleBufferType {
|
connecting = true
|
||||||
case .video:
|
super.connect(command, arguments: arguments)
|
||||||
stream.mixer.videoIO.captureOutput(nil, didOutputSampleBuffer: sampleBuffer, from: nil)
|
|
||||||
case .audioApp:
|
|
||||||
break
|
|
||||||
case .audioMic:
|
|
||||||
stream.mixer.audioIO.captureOutput(nil, didOutputSampleBuffer: sampleBuffer, from: nil)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override public func close() {
|
||||||
|
connecting = false
|
||||||
|
super.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func processMP4Clip(mp4ClipURL: URL?, completionHandler: MP4Sampler.Handler) {
|
||||||
|
guard let url:URL = mp4ClipURL else {
|
||||||
|
completionHandler()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
stream.append(url: url)
|
||||||
|
completionHandler()
|
||||||
|
}
|
||||||
|
|
||||||
override func on(status:Notification) {
|
override func on(status:Notification) {
|
||||||
super.on(status: status)
|
super.on(status: status)
|
||||||
let e:Event = Event.from(status)
|
let e:Event = Event.from(status)
|
||||||
|
@ -27,8 +46,7 @@ public class RTMPBroadcaster: RTMPConnection {
|
||||||
}
|
}
|
||||||
switch code {
|
switch code {
|
||||||
case RTMPConnection.Code.connectSuccess.rawValue:
|
case RTMPConnection.Code.connectSuccess.rawValue:
|
||||||
stream = RTMPStream(connection: self)
|
stream.publish("live")
|
||||||
stream?.publish("live")
|
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -36,34 +54,21 @@ public class RTMPBroadcaster: RTMPConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(iOS 10.0, *)
|
@available(iOS 10.0, *)
|
||||||
open class RTMPSampleHandler: RPBroadcastSampleHandler {
|
open class RTMPMP4ClipHandler: RPBroadcastMP4ClipHandler {
|
||||||
|
|
||||||
public static var broadcaster:RTMPBroadcaster?
|
deinit {
|
||||||
|
logger.info("deinit: \(self)")
|
||||||
|
}
|
||||||
|
|
||||||
override open func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?) {
|
override open func processMP4Clip(with mp4ClipURL: URL?, setupInfo: [String : NSObject]?, finished: Bool) {
|
||||||
logger.info("broadcastStarted:\(setupInfo)")
|
|
||||||
guard let endpointURL:String = setupInfo?["endpointURL"] as? String else {
|
guard let endpointURL:String = setupInfo?["endpointURL"] as? String else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
RTMPSampleHandler.broadcaster = RTMPBroadcaster()
|
RTMPBroadcaster.default.connect(endpointURL, arguments: nil)
|
||||||
RTMPSampleHandler.broadcaster?.connect(endpointURL, arguments: nil)
|
RTMPBroadcaster.default.processMP4Clip(mp4ClipURL: mp4ClipURL) {_ in
|
||||||
|
if (finished) {
|
||||||
|
RTMPBroadcaster.default.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
override open func broadcastPaused() {
|
|
||||||
logger.info("broadcastPaused")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override open func broadcastResumed() {
|
|
||||||
logger.info("broadcastResumed")
|
|
||||||
}
|
|
||||||
|
|
||||||
override open func broadcastFinished() {
|
|
||||||
logger.info("broadcastFinished")
|
|
||||||
RTMPSampleHandler.broadcaster?.close()
|
|
||||||
RTMPSampleHandler.broadcaster = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
override open func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
|
|
||||||
RTMPSampleHandler.broadcaster?.process(sampleBuffer: sampleBuffer, with: sampleBufferType)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,13 +37,16 @@ class MP4Box {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var leafNode:Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
fileprivate(set) var type:String = "undf"
|
fileprivate(set) var type:String = "undf"
|
||||||
fileprivate(set) var size:UInt32 = 0
|
fileprivate(set) var size:UInt32 = 0
|
||||||
fileprivate(set) var offset:UInt64 = 0
|
fileprivate(set) var offset:UInt64 = 0
|
||||||
fileprivate(set) var parent:MP4Box? = nil
|
fileprivate(set) var parent:MP4Box? = nil
|
||||||
|
|
||||||
var leafNode:Bool {
|
init() {
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init(size: UInt32, type:String) {
|
init(size: UInt32, type:String) {
|
||||||
|
@ -51,7 +54,7 @@ class MP4Box {
|
||||||
self.type = type
|
self.type = type
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
func load(_ fileHandle:FileHandle) throws -> UInt32 {
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
size = UInt32(fileHandle.seekToEndOfFile() - offset)
|
size = UInt32(fileHandle.seekToEndOfFile() - offset)
|
||||||
return size
|
return size
|
||||||
|
@ -60,7 +63,7 @@ class MP4Box {
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBoxesByName(_ name:String) -> [MP4Box] {
|
func getBoxes(byName:String) -> [MP4Box] {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,8 +79,8 @@ class MP4Box {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: CustomStringConvertible
|
|
||||||
extension MP4Box: CustomStringConvertible {
|
extension MP4Box: CustomStringConvertible {
|
||||||
|
// MARK: CustomStringConvertible
|
||||||
var description:String {
|
var description:String {
|
||||||
return Mirror(reflecting: self).description
|
return Mirror(reflecting: self).description
|
||||||
}
|
}
|
||||||
|
@ -92,29 +95,29 @@ class MP4ContainerBox: MP4Box {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
override func load(_ file:FileHandle) throws -> UInt32 {
|
||||||
children.removeAll(keepingCapacity: false)
|
children.removeAll(keepingCapacity: false)
|
||||||
|
|
||||||
var offset:UInt32 = parent == nil ? 0 : 8
|
var offset:UInt32 = parent == nil ? 0 : 8
|
||||||
fileHandle.seek(toFileOffset: self.offset + UInt64(offset))
|
file.seek(toFileOffset: self.offset + UInt64(offset))
|
||||||
|
|
||||||
while (size != offset) {
|
while (size != offset) {
|
||||||
let child:MP4Box = try create(fileHandle.readData(ofLength: 8), offset: offset)
|
let child:MP4Box = try create(file.readData(ofLength: 8), offset: offset)
|
||||||
offset += try child.loadFile(fileHandle)
|
offset += try child.load(file)
|
||||||
children.append(child)
|
children.append(child)
|
||||||
}
|
}
|
||||||
|
|
||||||
return offset
|
return offset
|
||||||
}
|
}
|
||||||
|
|
||||||
override func getBoxesByName(_ name:String) -> [MP4Box] {
|
override func getBoxes(byName:String) -> [MP4Box] {
|
||||||
var list:[MP4Box] = []
|
var list:[MP4Box] = []
|
||||||
for child in children {
|
for child in children {
|
||||||
if (name == child.type || name == "*" ) {
|
if (byName == child.type || byName == "*" ) {
|
||||||
list.append(child)
|
list.append(child)
|
||||||
}
|
}
|
||||||
if (!child.leafNode) {
|
if (!child.leafNode) {
|
||||||
list += child.getBoxesByName(name)
|
list += child.getBoxes(byName: byName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
|
@ -139,7 +142,7 @@ final class MP4MediaHeaderBox: MP4Box {
|
||||||
var language:UInt16 = 0
|
var language:UInt16 = 0
|
||||||
var quality:UInt16 = 0
|
var quality:UInt16 = 0
|
||||||
|
|
||||||
override func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
override func load(_ fileHandle: FileHandle) throws -> UInt32 {
|
||||||
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
||||||
version = try buffer.readUInt8()
|
version = try buffer.readUInt8()
|
||||||
buffer.position += 3
|
buffer.position += 3
|
||||||
|
@ -158,7 +161,7 @@ final class MP4MediaHeaderBox: MP4Box {
|
||||||
final class MP4ChunkOffsetBox: MP4Box {
|
final class MP4ChunkOffsetBox: MP4Box {
|
||||||
var entries:[UInt32] = []
|
var entries:[UInt32] = []
|
||||||
|
|
||||||
override func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
override func load(_ fileHandle: FileHandle) throws -> UInt32 {
|
||||||
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
||||||
buffer.position += 4
|
buffer.position += 4
|
||||||
|
|
||||||
|
@ -176,7 +179,7 @@ final class MP4ChunkOffsetBox: MP4Box {
|
||||||
final class MP4SyncSampleBox: MP4Box {
|
final class MP4SyncSampleBox: MP4Box {
|
||||||
var entries:[UInt32] = []
|
var entries:[UInt32] = []
|
||||||
|
|
||||||
override func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
override func load(_ fileHandle: FileHandle) throws -> UInt32 {
|
||||||
entries.removeAll(keepingCapacity: false)
|
entries.removeAll(keepingCapacity: false)
|
||||||
|
|
||||||
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
||||||
|
@ -209,7 +212,7 @@ final class MP4TimeToSampleBox: MP4Box {
|
||||||
|
|
||||||
var entries:[Entry] = []
|
var entries:[Entry] = []
|
||||||
|
|
||||||
override func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
override func load(_ fileHandle: FileHandle) throws -> UInt32 {
|
||||||
entries.removeAll(keepingCapacity: false)
|
entries.removeAll(keepingCapacity: false)
|
||||||
|
|
||||||
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
||||||
|
@ -231,7 +234,7 @@ final class MP4TimeToSampleBox: MP4Box {
|
||||||
final class MP4SampleSizeBox: MP4Box {
|
final class MP4SampleSizeBox: MP4Box {
|
||||||
var entries:[UInt32] = []
|
var entries:[UInt32] = []
|
||||||
|
|
||||||
override func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
override func load(_ fileHandle: FileHandle) throws -> UInt32 {
|
||||||
entries.removeAll(keepingCapacity: false)
|
entries.removeAll(keepingCapacity: false)
|
||||||
|
|
||||||
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(self.size) - 8))
|
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(self.size) - 8))
|
||||||
|
@ -266,7 +269,7 @@ final class MP4ElementaryStreamDescriptorBox: MP4ContainerBox {
|
||||||
var ocrStreamFlag:UInt8 = 0
|
var ocrStreamFlag:UInt8 = 0
|
||||||
var streamPriority:UInt8 = 0
|
var streamPriority:UInt8 = 0
|
||||||
|
|
||||||
override func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
override func load(_ fileHandle: FileHandle) throws -> UInt32 {
|
||||||
var tagSize:UInt8 = 0
|
var tagSize:UInt8 = 0
|
||||||
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(self.size) - 8))
|
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(self.size) - 8))
|
||||||
buffer.position += 4
|
buffer.position += 4
|
||||||
|
@ -329,7 +332,7 @@ final class MP4AudioSampleEntryBox: MP4ContainerBox {
|
||||||
|
|
||||||
var soundVersion2Data:[UInt8] = []
|
var soundVersion2Data:[UInt8] = []
|
||||||
|
|
||||||
override func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
override func load(_ fileHandle: FileHandle) throws -> UInt32 {
|
||||||
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
||||||
buffer.position += 8
|
buffer.position += 8
|
||||||
|
|
||||||
|
@ -361,7 +364,7 @@ final class MP4AudioSampleEntryBox: MP4ContainerBox {
|
||||||
fileHandle.seek(toFileOffset: self.offset + UInt64(offset))
|
fileHandle.seek(toFileOffset: self.offset + UInt64(offset))
|
||||||
|
|
||||||
let esds:MP4Box = try create(fileHandle.readData(ofLength: 8), offset: offset)
|
let esds:MP4Box = try create(fileHandle.readData(ofLength: 8), offset: offset)
|
||||||
offset += try esds.loadFile(fileHandle)
|
offset += try esds.load(fileHandle)
|
||||||
children.append(esds)
|
children.append(esds)
|
||||||
|
|
||||||
// skip
|
// skip
|
||||||
|
@ -383,7 +386,7 @@ final class MP4VisualSampleEntryBox: MP4ContainerBox {
|
||||||
var compressorname:String = ""
|
var compressorname:String = ""
|
||||||
var depth:UInt16 = 16
|
var depth:UInt16 = 16
|
||||||
|
|
||||||
override func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
override func load(_ fileHandle: FileHandle) throws -> UInt32 {
|
||||||
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: MP4VisualSampleEntryBox.dataSize))
|
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: MP4VisualSampleEntryBox.dataSize))
|
||||||
|
|
||||||
buffer.position += 24
|
buffer.position += 24
|
||||||
|
@ -402,7 +405,7 @@ final class MP4VisualSampleEntryBox: MP4ContainerBox {
|
||||||
let child:MP4Box = try MP4Box.create(fileHandle.readData(ofLength: 8))
|
let child:MP4Box = try MP4Box.create(fileHandle.readData(ofLength: 8))
|
||||||
child.parent = self
|
child.parent = self
|
||||||
child.offset = self.offset + UInt64(offset) + 8
|
child.offset = self.offset + UInt64(offset) + 8
|
||||||
offset += try child.loadFile(fileHandle)
|
offset += try child.load(fileHandle)
|
||||||
children.append(child)
|
children.append(child)
|
||||||
|
|
||||||
// skip
|
// skip
|
||||||
|
@ -414,7 +417,7 @@ final class MP4VisualSampleEntryBox: MP4ContainerBox {
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
final class MP4SampleDescriptionBox: MP4ContainerBox {
|
final class MP4SampleDescriptionBox: MP4ContainerBox {
|
||||||
override func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
override func load(_ fileHandle: FileHandle) throws -> UInt32 {
|
||||||
children.removeAll(keepingCapacity: false)
|
children.removeAll(keepingCapacity: false)
|
||||||
|
|
||||||
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: 8))
|
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: 8))
|
||||||
|
@ -424,7 +427,7 @@ final class MP4SampleDescriptionBox: MP4ContainerBox {
|
||||||
let numberOfEntries:UInt32 = try buffer.readUInt32()
|
let numberOfEntries:UInt32 = try buffer.readUInt32()
|
||||||
for _ in 0..<numberOfEntries {
|
for _ in 0..<numberOfEntries {
|
||||||
let child:MP4Box = try create(fileHandle.readData(ofLength: 8), offset: offset)
|
let child:MP4Box = try create(fileHandle.readData(ofLength: 8), offset: offset)
|
||||||
offset += try child.loadFile(fileHandle)
|
offset += try child.load(fileHandle)
|
||||||
children.append(child)
|
children.append(child)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +455,7 @@ final class MP4SampleToChunkBox: MP4Box {
|
||||||
|
|
||||||
var entries:[Entry] = []
|
var entries:[Entry] = []
|
||||||
|
|
||||||
override func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
override func load(_ fileHandle: FileHandle) throws -> UInt32 {
|
||||||
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
||||||
buffer.position += 4
|
buffer.position += 4
|
||||||
|
|
||||||
|
@ -491,7 +494,7 @@ final class MP4EditListBox: MP4Box {
|
||||||
var version:UInt32 = 0
|
var version:UInt32 = 0
|
||||||
var entries:[Entry] = []
|
var entries:[Entry] = []
|
||||||
|
|
||||||
override func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
override func load(_ fileHandle: FileHandle) throws -> UInt32 {
|
||||||
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
let buffer:ByteArray = ByteArray(data: fileHandle.readData(ofLength: Int(size) - 8))
|
||||||
|
|
||||||
version = try buffer.readUInt32()
|
version = try buffer.readUInt32()
|
||||||
|
@ -511,7 +514,7 @@ final class MP4EditListBox: MP4Box {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
final class MP4File: MP4ContainerBox {
|
final class MP4Reader: MP4ContainerBox {
|
||||||
var url:URL? = nil {
|
var url:URL? = nil {
|
||||||
didSet {
|
didSet {
|
||||||
if (url == nil) {
|
if (url == nil) {
|
||||||
|
@ -525,46 +528,46 @@ final class MP4File: MP4ContainerBox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate var fileHandle:FileHandle? = nil
|
var isEmpty:Bool {
|
||||||
|
return getBoxes(byName: "mdhd").isEmpty
|
||||||
func isEmpty() -> Bool {
|
|
||||||
return getBoxesByName("mdhd").isEmpty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readDataOfLength(_ length: Int) -> Data {
|
private var fileHandle:FileHandle? = nil
|
||||||
return fileHandle!.readData(ofLength: length)
|
|
||||||
|
func seek(toFileOffset: UInt64) {
|
||||||
|
return fileHandle!.seek(toFileOffset: toFileOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func seekToFileOffset(_ offset: UInt64) {
|
func readData(ofLength: Int) -> Data {
|
||||||
return fileHandle!.seek(toFileOffset: offset)
|
return fileHandle!.readData(ofLength: ofLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readDataOfBox(_ box:MP4Box) -> Data {
|
func readData(ofBox:MP4Box) -> Data {
|
||||||
if (fileHandle == nil) {
|
guard let fileHandle:FileHandle = fileHandle else {
|
||||||
return Data()
|
return Data()
|
||||||
}
|
}
|
||||||
let currentOffsetInFile:UInt64 = fileHandle!.offsetInFile
|
let currentOffsetInFile:UInt64 = fileHandle.offsetInFile
|
||||||
fileHandle!.seek(toFileOffset: box.offset + 8)
|
fileHandle.seek(toFileOffset: ofBox.offset + 8)
|
||||||
let data:Data = fileHandle!.readData(ofLength: Int(box.size) - 8)
|
let data:Data = fileHandle.readData(ofLength: Int(ofBox.size) - 8)
|
||||||
fileHandle!.seek(toFileOffset: currentOffsetInFile)
|
fileHandle.seek(toFileOffset: currentOffsetInFile)
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadFile() throws -> UInt32 {
|
func load() throws -> UInt32 {
|
||||||
if (fileHandle == nil) {
|
guard let fileHandle:FileHandle = self.fileHandle else {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return try self.loadFile(fileHandle!)
|
return try load(fileHandle)
|
||||||
}
|
}
|
||||||
|
|
||||||
func closeFile() {
|
func close() {
|
||||||
fileHandle?.closeFile()
|
fileHandle?.closeFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func loadFile(_ fileHandle: FileHandle) throws -> UInt32 {
|
override func load(_ fileHandle: FileHandle) throws -> UInt32 {
|
||||||
let size:UInt64 = fileHandle.seekToEndOfFile()
|
let size:UInt64 = fileHandle.seekToEndOfFile()
|
||||||
fileHandle.seek(toFileOffset: 0)
|
fileHandle.seek(toFileOffset: 0)
|
||||||
self.size = UInt32(size)
|
self.size = UInt32(size)
|
||||||
return try super.loadFile(fileHandle)
|
return try super.load(fileHandle)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,215 @@
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct MP4SampleTable {
|
||||||
|
var trak:MP4Box
|
||||||
|
var currentOffset:UInt64 {
|
||||||
|
return UInt64(offset[cursor])
|
||||||
|
}
|
||||||
|
var currentIsKeyframe:Bool {
|
||||||
|
return keyframe[cursor] != nil
|
||||||
|
}
|
||||||
|
var currentDuration:Double {
|
||||||
|
return Double(totalTimeToSample) * 1000 / Double(timeScale)
|
||||||
|
}
|
||||||
|
var currentTimeToSample:Double {
|
||||||
|
return Double(timeToSample[cursor]) * 1000 / Double(timeScale)
|
||||||
|
}
|
||||||
|
var currentSampleSize:Int {
|
||||||
|
return Int((sampleSize.count == 1) ? sampleSize[0] : sampleSize[cursor])
|
||||||
|
}
|
||||||
|
private var cursor:Int = 0
|
||||||
|
private var offset:[UInt32] = []
|
||||||
|
private var keyframe:[Int:Bool] = [:]
|
||||||
|
private var timeScale:UInt32 = 0
|
||||||
|
private var sampleSize:[UInt32] = []
|
||||||
|
private var timeToSample:[UInt32] = []
|
||||||
|
private var totalTimeToSample:UInt32 = 0
|
||||||
|
|
||||||
|
init(trak:MP4Box) {
|
||||||
|
self.trak = trak
|
||||||
|
|
||||||
|
let mdhd:MP4Box? = trak.getBoxes(byName: "mdhd").first
|
||||||
|
if let mdhd:MP4MediaHeaderBox = mdhd as? MP4MediaHeaderBox {
|
||||||
|
timeScale = mdhd.timeScale
|
||||||
|
}
|
||||||
|
|
||||||
|
let stss:MP4Box? = trak.getBoxes(byName: "stss").first
|
||||||
|
if let stss:MP4SyncSampleBox = stss as? MP4SyncSampleBox {
|
||||||
|
var keyframes:[UInt32] = stss.entries
|
||||||
|
for i in 0..<keyframes.count {
|
||||||
|
keyframe[Int(keyframes[i])] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let stts:MP4Box? = trak.getBoxes(byName: "stts").first
|
||||||
|
if let stts:MP4TimeToSampleBox = stts as? MP4TimeToSampleBox {
|
||||||
|
var timeToSample:[MP4TimeToSampleBox.Entry] = stts.entries
|
||||||
|
for i in 0..<timeToSample.count {
|
||||||
|
let entry:MP4TimeToSampleBox.Entry = timeToSample[i]
|
||||||
|
for _ in 0..<entry.sampleCount {
|
||||||
|
self.timeToSample.append(entry.sampleDuration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let stsz:MP4Box? = trak.getBoxes(byName: "stsz").first
|
||||||
|
if let stsz:MP4SampleSizeBox = stsz as? MP4SampleSizeBox {
|
||||||
|
sampleSize = stsz.entries
|
||||||
|
}
|
||||||
|
|
||||||
|
let stco:MP4Box = trak.getBoxes(byName: "stco").first!
|
||||||
|
let stsc:MP4Box = trak.getBoxes(byName: "stsc").first!
|
||||||
|
var offsets:[UInt32] = (stco as! MP4ChunkOffsetBox).entries
|
||||||
|
var sampleToChunk:[MP4SampleToChunkBox.Entry] = (stsc as! MP4SampleToChunkBox).entries
|
||||||
|
|
||||||
|
var index:Int = 0
|
||||||
|
let count:Int = sampleToChunk.count
|
||||||
|
|
||||||
|
for i in 0..<count {
|
||||||
|
let j:Int = Int(sampleToChunk[i].firstChunk) - 1
|
||||||
|
let m:Int = (i + 1 < count) ? Int(sampleToChunk[i + 1].firstChunk) - 1 : offsets.count
|
||||||
|
for _ in j..<m {
|
||||||
|
var offset:UInt32 = offsets[j]
|
||||||
|
for _ in 0..<sampleToChunk[i].samplesPerChunk {
|
||||||
|
self.offset.append(offset)
|
||||||
|
offset += sampleSize[index]
|
||||||
|
index += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
totalTimeToSample = timeToSample[cursor]
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasNext() -> Bool {
|
||||||
|
return cursor + 1 < offset.count
|
||||||
|
}
|
||||||
|
|
||||||
|
mutating func next() {
|
||||||
|
defer {
|
||||||
|
cursor += 1
|
||||||
|
}
|
||||||
|
totalTimeToSample += timeToSample[cursor]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MP4SampleTable: CustomStringConvertible {
|
||||||
|
// MARK: CustomStringConvertible
|
||||||
|
var description:String {
|
||||||
|
return Mirror(reflecting: self).description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
protocol MP4SamplerDelegate: class {
|
||||||
|
func didSet(avcC: Data, withType:Int)
|
||||||
|
func didSet(audioDecorderSpecificConfig: Data, withType:Int)
|
||||||
|
func output(data: Data, withType:Int, currentTime:Double, keyframe:Bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
class MP4Sampler {
|
||||||
|
typealias Handler = () -> Void
|
||||||
|
|
||||||
|
weak var delegate:MP4SamplerDelegate?
|
||||||
|
|
||||||
|
fileprivate(set) var running:Bool = false
|
||||||
|
fileprivate var files:[URL:Handler?] = [:]
|
||||||
|
fileprivate let fileQueue:DispatchQueue = DispatchQueue(label: "com.github.shogo4405.lf.MP4Sampler.file")
|
||||||
|
fileprivate let lockQueue:DispatchQueue = DispatchQueue(label: "com.github.shgoo4405.lf.MP4Sampler.lock")
|
||||||
|
|
||||||
|
private var reader:MP4Reader = MP4Reader()
|
||||||
|
private var sampleTables:[MP4SampleTable] = []
|
||||||
|
|
||||||
|
func append(file:URL, completionHandler: Handler? = nil) {
|
||||||
|
fileQueue.async {
|
||||||
|
self.files[file] = completionHandler
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func execute(url:URL) {
|
||||||
|
|
||||||
|
reader.url = url
|
||||||
|
|
||||||
|
do {
|
||||||
|
let _:UInt32 = try reader.load()
|
||||||
|
} catch {
|
||||||
|
logger.warning("")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sampleTables.removeAll()
|
||||||
|
var traks:[MP4Box] = reader.getBoxes(byName: "trak")
|
||||||
|
for i in 0..<traks.count {
|
||||||
|
sampleTables.append(MP4SampleTable(trak: traks[i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..<sampleTables.count {
|
||||||
|
if let avcC:MP4Box = sampleTables[i].trak.getBoxes(byName: "avcC").first {
|
||||||
|
delegate?.didSet(avcC: reader.readData(ofBox: avcC), withType: i)
|
||||||
|
}
|
||||||
|
if let esds:MP4ElementaryStreamDescriptorBox = sampleTables[i].trak.getBoxes(byName: "esds").first as? MP4ElementaryStreamDescriptorBox {
|
||||||
|
delegate?.didSet(audioDecorderSpecificConfig: Data(esds.audioDecorderSpecificConfig), withType: i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repeat {
|
||||||
|
for i in 0..<sampleTables.count {
|
||||||
|
autoreleasepool {
|
||||||
|
reader.seek(toFileOffset: sampleTables[i].currentOffset)
|
||||||
|
let length:Int = sampleTables[i].currentSampleSize
|
||||||
|
delegate?.output(
|
||||||
|
data: reader.readData(ofLength: length),
|
||||||
|
withType: i,
|
||||||
|
currentTime: sampleTables[i].currentTimeToSample,
|
||||||
|
keyframe: sampleTables[i].currentIsKeyframe
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (sampleTables[i].hasNext()) {
|
||||||
|
sampleTables[i].next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while inLoop(sampleTables: sampleTables)
|
||||||
|
|
||||||
|
reader.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func run() {
|
||||||
|
if (files.isEmpty) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let (key: url, value: handler) = files.popFirst()!
|
||||||
|
execute(url: url)
|
||||||
|
handler?()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func inLoop(sampleTables:[MP4SampleTable]) -> Bool{
|
||||||
|
for i in sampleTables {
|
||||||
|
if (i.hasNext()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MP4Sampler: Runnable {
|
||||||
|
// MARK: Runnable
|
||||||
|
final func startRunning() {
|
||||||
|
lockQueue.async {
|
||||||
|
self.running = true
|
||||||
|
while (self.running) {
|
||||||
|
self.fileQueue.async {
|
||||||
|
self.run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final func stopRunning() {
|
||||||
|
lockQueue.async {
|
||||||
|
self.running = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -194,7 +194,7 @@ struct PacketizedElementaryStream: PESPacketHeader {
|
||||||
packet.adaptationFieldFlag = true
|
packet.adaptationFieldFlag = true
|
||||||
packet.adaptationField = TSAdaptationField()
|
packet.adaptationField = TSAdaptationField()
|
||||||
packet.adaptationField?.PCRFlag = true
|
packet.adaptationField?.PCRFlag = true
|
||||||
packet.adaptationField?.PCR = TSProgramClockReference.encode(0, UInt16(PCR))
|
packet.adaptationField?.PCR = TSProgramClockReference.encode(PCR, 0)
|
||||||
packet.adaptationField?.compute()
|
packet.adaptationField?.compute()
|
||||||
}
|
}
|
||||||
packet.payloadUnitStartIndicator = true
|
packet.payloadUnitStartIndicator = true
|
||||||
|
|
|
@ -58,10 +58,11 @@ class TSWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeSampleBuffer(_ PID:UInt16, streamID:UInt8, sampleBuffer:CMSampleBuffer) {
|
func writeSampleBuffer(_ PID:UInt16, streamID:UInt8, sampleBuffer:CMSampleBuffer) {
|
||||||
|
let presentationTimeStamp:CMTime = sampleBuffer.presentationTimeStamp
|
||||||
if (timestamps[PID] == nil) {
|
if (timestamps[PID] == nil) {
|
||||||
timestamps[PID] = sampleBuffer.presentationTimeStamp
|
timestamps[PID] = presentationTimeStamp
|
||||||
if (PCRPID == PID) {
|
if (PCRPID == PID) {
|
||||||
PCRTimestamp = sampleBuffer.presentationTimeStamp
|
PCRTimestamp = presentationTimeStamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let config:Any? = streamID == 192 ? audioConfig : videoConfig
|
let config:Any? = streamID == 192 ? audioConfig : videoConfig
|
||||||
|
@ -71,9 +72,14 @@ class TSWriter {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
PES.streamID = streamID
|
PES.streamID = streamID
|
||||||
let decodeTimeStamp:CMTime = sampleBuffer.decodeTimeStamp
|
|
||||||
|
var decodeTimeStamp:CMTime = sampleBuffer.decodeTimeStamp
|
||||||
|
if (decodeTimeStamp == kCMTimeInvalid) {
|
||||||
|
decodeTimeStamp = presentationTimeStamp
|
||||||
|
}
|
||||||
|
|
||||||
var packets:[TSPacket] = split(PID, PES: PES, timestamp: decodeTimeStamp)
|
var packets:[TSPacket] = split(PID, PES: PES, timestamp: decodeTimeStamp)
|
||||||
if (PCRPID == PID && rorateFileHandle(decodeTimeStamp, next: sampleBuffer.decodeTimeStamp)) {
|
if (PCRPID == PID && rorateFileHandle(decodeTimeStamp)) {
|
||||||
packets[0].adaptationField?.randomAccessIndicator = true
|
packets[0].adaptationField?.randomAccessIndicator = true
|
||||||
packets[0].adaptationField?.discontinuityIndicator = true
|
packets[0].adaptationField?.discontinuityIndicator = true
|
||||||
}
|
}
|
||||||
|
@ -106,7 +112,7 @@ class TSWriter {
|
||||||
return packets
|
return packets
|
||||||
}
|
}
|
||||||
|
|
||||||
func rorateFileHandle(_ timestamp:CMTime, next:CMTime) -> Bool {
|
func rorateFileHandle(_ timestamp:CMTime) -> Bool {
|
||||||
let duration:Double = timestamp.seconds - rotatedTimestamp.seconds
|
let duration:Double = timestamp.seconds - rotatedTimestamp.seconds
|
||||||
if (duration <= segmentDuration) {
|
if (duration <= segmentDuration) {
|
||||||
return false
|
return false
|
|
@ -10,7 +10,7 @@ final class NetClient: NetSocket {
|
||||||
static let defaultBufferSize:Int = 8192
|
static let defaultBufferSize:Int = 8192
|
||||||
|
|
||||||
weak var delegate:NetClientDelegate?
|
weak var delegate:NetClientDelegate?
|
||||||
fileprivate(set) var service:Foundation.NetService?
|
private(set) var service:Foundation.NetService?
|
||||||
|
|
||||||
init(service:Foundation.NetService, inputStream:InputStream, outputStream:OutputStream) {
|
init(service:Foundation.NetService, inputStream:InputStream, outputStream:OutputStream) {
|
||||||
super.init()
|
super.init()
|
||||||
|
|
|
@ -153,9 +153,7 @@ enum FLVAudioCodec:UInt8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
struct FLVTag {
|
enum FLVTagType:UInt8 {
|
||||||
|
|
||||||
enum TagType: UInt8 {
|
|
||||||
case audio = 8
|
case audio = 8
|
||||||
case video = 9
|
case video = 9
|
||||||
case data = 18
|
case data = 18
|
||||||
|
@ -182,7 +180,7 @@ struct FLVTag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMessage(_ streamId: UInt32, timestamp: UInt32, buffer:Foundation.Data) -> RTMPMessage {
|
func message(with streamId: UInt32, timestamp: UInt32, buffer:Data) -> RTMPMessage {
|
||||||
switch self {
|
switch self {
|
||||||
case .audio:
|
case .audio:
|
||||||
return RTMPAudioMessage(streamId: streamId, timestamp: timestamp, buffer: buffer)
|
return RTMPAudioMessage(streamId: streamId, timestamp: timestamp, buffer: buffer)
|
||||||
|
@ -192,11 +190,14 @@ struct FLVTag {
|
||||||
return RTMPDataMessage(objectEncoding: 0x00)
|
return RTMPDataMessage(objectEncoding: 0x00)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
struct FLVTag {
|
||||||
static let headerSize = 11
|
static let headerSize = 11
|
||||||
|
|
||||||
var tagType:TagType = .data
|
var tagType:FLVTagType = .data
|
||||||
var dataSize:UInt32 = 0
|
var dataSize:UInt32 = 0
|
||||||
var timestamp:UInt32 = 0
|
var timestamp:UInt32 = 0
|
||||||
var timestampExtended:UInt8 = 0
|
var timestampExtended:UInt8 = 0
|
||||||
|
|
|
@ -5,10 +5,12 @@ import Foundation
|
||||||
*/
|
*/
|
||||||
open class Responder: NSObject {
|
open class Responder: NSObject {
|
||||||
|
|
||||||
private var result:(_ data:[Any?]) -> Void
|
public typealias Handler = (_ data:[Any?]) -> Void
|
||||||
private var status:((_ data:[Any?]) -> Void)?
|
|
||||||
|
|
||||||
public init(result:@escaping (_ data:[Any?]) -> Void, status:((_ data:[Any?]) -> Void)? = nil) {
|
private var result:Handler
|
||||||
|
private var status:Handler?
|
||||||
|
|
||||||
|
public init(result:@escaping Handler, status:Handler? = nil) {
|
||||||
self.result = result
|
self.result = result
|
||||||
self.status = status
|
self.status = status
|
||||||
}
|
}
|
||||||
|
@ -330,18 +332,6 @@ open class RTMPConnection: EventDispatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func on(timer:Timer) {
|
|
||||||
let totalBytesIn:Int64 = self.totalBytesIn
|
|
||||||
let totalBytesOut:Int64 = self.totalBytesOut
|
|
||||||
currentBytesInPerSecond = Int32(totalBytesIn - previousTotalBytesIn)
|
|
||||||
currentBytesOutPerSecond = Int32(totalBytesOut - previousTotalBytesOut)
|
|
||||||
previousTotalBytesIn = totalBytesIn
|
|
||||||
previousTotalBytesOut = totalBytesOut
|
|
||||||
for (_, stream) in streams {
|
|
||||||
stream.on(timer: timer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate func createConnectionChunk() -> RTMPChunk? {
|
fileprivate func createConnectionChunk() -> RTMPChunk? {
|
||||||
guard let uri:URL = uri else {
|
guard let uri:URL = uri else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -378,6 +368,18 @@ open class RTMPConnection: EventDispatcher {
|
||||||
|
|
||||||
return RTMPChunk(message: message)
|
return RTMPChunk(message: message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func on(timer:Timer) {
|
||||||
|
let totalBytesIn:Int64 = self.totalBytesIn
|
||||||
|
let totalBytesOut:Int64 = self.totalBytesOut
|
||||||
|
currentBytesInPerSecond = Int32(totalBytesIn - previousTotalBytesIn)
|
||||||
|
currentBytesOutPerSecond = Int32(totalBytesOut - previousTotalBytesOut)
|
||||||
|
previousTotalBytesIn = totalBytesIn
|
||||||
|
previousTotalBytesOut = totalBytesOut
|
||||||
|
for (_, stream) in streams {
|
||||||
|
stream.on(timer: timer)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension RTMPConnection: RTMPSocketDelegate {
|
extension RTMPConnection: RTMPSocketDelegate {
|
||||||
|
|
|
@ -345,7 +345,7 @@ final class RTMPCommandMessage: RTMPMessage {
|
||||||
case "close":
|
case "close":
|
||||||
connection.close()
|
connection.close()
|
||||||
default:
|
default:
|
||||||
connection.dispatch(type: Event.RTMP_STATUS, bubbles: false, data: arguments.isEmpty ? nil : arguments[0])
|
connection.dispatch(Event.RTMP_STATUS, bubbles: false, data: arguments.isEmpty ? nil : arguments[0])
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -371,7 +371,7 @@ final class RTMPDataMessage: RTMPMessage {
|
||||||
var handlerName:String = ""
|
var handlerName:String = ""
|
||||||
var arguments:[Any?] = []
|
var arguments:[Any?] = []
|
||||||
|
|
||||||
fileprivate var serializer:AMFSerializer = AMF0Serializer()
|
private var serializer:AMFSerializer = AMF0Serializer()
|
||||||
|
|
||||||
override var payload:[UInt8] {
|
override var payload:[UInt8] {
|
||||||
get {
|
get {
|
||||||
|
@ -533,10 +533,10 @@ final class RTMPSharedObjectMessage: RTMPMessage {
|
||||||
final class RTMPAudioMessage: RTMPMessage {
|
final class RTMPAudioMessage: RTMPMessage {
|
||||||
var config:AudioSpecificConfig?
|
var config:AudioSpecificConfig?
|
||||||
|
|
||||||
fileprivate(set) var codec:FLVAudioCodec = .unknown
|
private(set) var codec:FLVAudioCodec = .unknown
|
||||||
fileprivate(set) var soundRate:FLVSoundRate = .kHz44
|
private(set) var soundRate:FLVSoundRate = .kHz44
|
||||||
fileprivate(set) var soundSize:FLVSoundSize = .snd8bit
|
private(set) var soundSize:FLVSoundSize = .snd8bit
|
||||||
fileprivate(set) var soundType:FLVSoundType = .stereo
|
private(set) var soundType:FLVSoundType = .stereo
|
||||||
|
|
||||||
var soundData:[UInt8] {
|
var soundData:[UInt8] {
|
||||||
let data:[UInt8] = payload.isEmpty ? [] : Array(payload[codec.headerSize..<payload.count])
|
let data:[UInt8] = payload.isEmpty ? [] : Array(payload[codec.headerSize..<payload.count])
|
||||||
|
@ -618,8 +618,8 @@ final class RTMPAudioMessage: RTMPMessage {
|
||||||
7.1.5. Video Message (9)
|
7.1.5. Video Message (9)
|
||||||
*/
|
*/
|
||||||
final class RTMPVideoMessage: RTMPMessage {
|
final class RTMPVideoMessage: RTMPMessage {
|
||||||
fileprivate(set) var codec:FLVVideoCodec = .unknown
|
private(set) var codec:FLVVideoCodec = .unknown
|
||||||
fileprivate(set) var status:OSStatus = noErr
|
private(set) var status:OSStatus = noErr
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
super.init(type: .video)
|
super.init(type: .video)
|
||||||
|
@ -638,7 +638,7 @@ final class RTMPVideoMessage: RTMPMessage {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
OSAtomicAdd64(Int64(payload.count), &stream.info.byteCount)
|
OSAtomicAdd64(Int64(payload.count), &stream.info.byteCount)
|
||||||
guard FLVTag.TagType.video.headerSize < payload.count else {
|
guard FLVTagType.video.headerSize < payload.count else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch payload[1] {
|
switch payload[1] {
|
||||||
|
@ -661,7 +661,7 @@ final class RTMPVideoMessage: RTMPMessage {
|
||||||
decodeTimeStamp: kCMTimeInvalid
|
decodeTimeStamp: kCMTimeInvalid
|
||||||
)
|
)
|
||||||
|
|
||||||
let bytes:[UInt8] = Array(payload[FLVTag.TagType.video.headerSize..<payload.count])
|
let bytes:[UInt8] = Array(payload[FLVTagType.video.headerSize..<payload.count])
|
||||||
var sample:[UInt8] = bytes
|
var sample:[UInt8] = bytes
|
||||||
let sampleSize:Int = bytes.count
|
let sampleSize:Int = bytes.count
|
||||||
var blockBuffer:CMBlockBuffer?
|
var blockBuffer:CMBlockBuffer?
|
||||||
|
@ -680,7 +680,7 @@ final class RTMPVideoMessage: RTMPMessage {
|
||||||
|
|
||||||
func createFormatDescription(_ stream: RTMPStream) -> OSStatus {
|
func createFormatDescription(_ stream: RTMPStream) -> OSStatus {
|
||||||
var config:AVCConfigurationRecord = AVCConfigurationRecord()
|
var config:AVCConfigurationRecord = AVCConfigurationRecord()
|
||||||
config.bytes = Array(payload[FLVTag.TagType.video.headerSize..<payload.count])
|
config.bytes = Array(payload[FLVTagType.video.headerSize..<payload.count])
|
||||||
return config.createFormatDescription(&stream.mixer.videoIO.formatDescription)
|
return config.createFormatDescription(&stream.mixer.videoIO.formatDescription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -764,7 +764,7 @@ final class RTMPUserControlMessage: RTMPMessage {
|
||||||
message: RTMPUserControlMessage(event: .pong, value: value)
|
message: RTMPUserControlMessage(event: .pong, value: value)
|
||||||
))
|
))
|
||||||
case .bufferEmpty, .bufferFull:
|
case .bufferEmpty, .bufferFull:
|
||||||
connection.streams[UInt32(value)]?.dispatch(type: "rtmpStatus", bubbles: false, data: [
|
connection.streams[UInt32(value)]?.dispatch("rtmpStatus", bubbles: false, data: [
|
||||||
"level": "status",
|
"level": "status",
|
||||||
"code": description,
|
"code": description,
|
||||||
"description": ""
|
"description": ""
|
||||||
|
|
|
@ -8,8 +8,12 @@ protocol RTMPMuxerDelegate: class {
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
final class RTMPMuxer {
|
final class RTMPMuxer {
|
||||||
weak var delegate:RTMPMuxerDelegate? = nil
|
static let aac:UInt8 = FLVAudioCodec.aac.rawValue << 4 | FLVSoundRate.kHz44.rawValue << 2 | FLVSoundSize.snd16bit.rawValue << 1 | FLVSoundType.stereo.rawValue
|
||||||
|
|
||||||
|
weak var delegate:RTMPMuxerDelegate? = nil
|
||||||
|
fileprivate var avcC:Data?
|
||||||
|
fileprivate var audioDecorderSpecificConfig:Data?
|
||||||
|
fileprivate var timestamps:[Int:Double] = [:]
|
||||||
fileprivate var audioTimestamp:CMTime = kCMTimeZero
|
fileprivate var audioTimestamp:CMTime = kCMTimeZero
|
||||||
fileprivate var videoTimestamp:CMTime = kCMTimeZero
|
fileprivate var videoTimestamp:CMTime = kCMTimeZero
|
||||||
|
|
||||||
|
@ -21,7 +25,6 @@ final class RTMPMuxer {
|
||||||
|
|
||||||
extension RTMPMuxer: AudioEncoderDelegate {
|
extension RTMPMuxer: AudioEncoderDelegate {
|
||||||
// MARK: AudioEncoderDelegate
|
// MARK: AudioEncoderDelegate
|
||||||
private static let aac:UInt8 = FLVAudioCodec.aac.rawValue << 4 | FLVSoundRate.kHz44.rawValue << 2 | FLVSoundSize.snd16bit.rawValue << 1 | FLVSoundType.stereo.rawValue
|
|
||||||
|
|
||||||
func didSetFormatDescription(audio formatDescription: CMFormatDescription?) {
|
func didSetFormatDescription(audio formatDescription: CMFormatDescription?) {
|
||||||
guard let formatDescription:CMFormatDescription = formatDescription else {
|
guard let formatDescription:CMFormatDescription = formatDescription else {
|
||||||
|
@ -95,3 +98,49 @@ extension RTMPMuxer: VideoEncoderDelegate {
|
||||||
videoTimestamp = decodeTimeStamp
|
videoTimestamp = decodeTimeStamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension RTMPMuxer: MP4SamplerDelegate {
|
||||||
|
// MP4SampleDelegate
|
||||||
|
func didSet(avcC: Data, withType:Int) {
|
||||||
|
if (avcC == self.avcC) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var buffer:Data = Data([FLVFrameType.key.rawValue << 4 | FLVVideoCodec.avc.rawValue, FLVAVCPacketType.seq.rawValue, 0, 0, 0])
|
||||||
|
buffer.append(avcC)
|
||||||
|
delegate?.sampleOutput(video: buffer, withTimestamp: 0, muxer: self)
|
||||||
|
self.avcC = avcC
|
||||||
|
}
|
||||||
|
|
||||||
|
func didSet(audioDecorderSpecificConfig: Data, withType:Int) {
|
||||||
|
if (withType == 2) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (audioDecorderSpecificConfig == self.audioDecorderSpecificConfig) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var buffer:Data = Data([RTMPMuxer.aac, FLVAACPacketType.raw.rawValue])
|
||||||
|
buffer.append(audioDecorderSpecificConfig)
|
||||||
|
delegate?.sampleOutput(audio: buffer, withTimestamp: 0, muxer: self)
|
||||||
|
self.audioDecorderSpecificConfig = audioDecorderSpecificConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func output(data:Data, withType:Int, currentTime:Double, keyframe:Bool) {
|
||||||
|
let delta:Double = (timestamps[withType] == nil) ? 0 : timestamps[withType]!
|
||||||
|
switch withType {
|
||||||
|
case 0:
|
||||||
|
print(delta)
|
||||||
|
let compositionTime:Int32 = 0
|
||||||
|
var buffer:Data = Data([((keyframe ? FLVFrameType.key.rawValue : FLVFrameType.inter.rawValue) << 4) | FLVVideoCodec.avc.rawValue, FLVAVCPacketType.nal.rawValue])
|
||||||
|
buffer.append(contentsOf: compositionTime.bigEndian.bytes[1..<4])
|
||||||
|
buffer.append(data)
|
||||||
|
delegate?.sampleOutput(video: buffer, withTimestamp: delta, muxer: self)
|
||||||
|
case 1:
|
||||||
|
var buffer:Data = Data([RTMPMuxer.aac, FLVAACPacketType.raw.rawValue])
|
||||||
|
buffer.append(data)
|
||||||
|
delegate?.sampleOutput(audio: buffer, withTimestamp: delta, muxer: self)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
timestamps[withType] = currentTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -192,7 +192,7 @@ open class RTMPSharedObject: EventDispatcher {
|
||||||
}
|
}
|
||||||
changeList.append(change)
|
changeList.append(change)
|
||||||
}
|
}
|
||||||
dispatch(type: Event.SYNC, bubbles: false, data: changeList)
|
dispatch(Event.SYNC, bubbles: false, data: changeList)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createChunk(_ events:[RTMPSharedObjectEvent]) -> RTMPChunk {
|
func createChunk(_ events:[RTMPSharedObjectEvent]) -> RTMPChunk {
|
||||||
|
|
|
@ -150,7 +150,7 @@ final class RTMPSocket: NetSocket, RTMPSocketCompatible {
|
||||||
|
|
||||||
override func didTimeout() {
|
override func didTimeout() {
|
||||||
deinitConnection(isDisconnected: false)
|
deinitConnection(isDisconnected: false)
|
||||||
delegate?.dispatch(type: Event.IO_ERROR, bubbles: false, data: nil)
|
delegate?.dispatch(Event.IO_ERROR, bubbles: false, data: nil)
|
||||||
logger.warning("connection timedout")
|
logger.warning("connection timedout")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,7 +224,7 @@ open class RTMPStream: NetStream {
|
||||||
open static let defaultVideoBitrate:UInt32 = AVCEncoder.defaultBitrate
|
open static let defaultVideoBitrate:UInt32 = AVCEncoder.defaultBitrate
|
||||||
open internal(set) var info:RTMPStreamInfo = RTMPStreamInfo()
|
open internal(set) var info:RTMPStreamInfo = RTMPStreamInfo()
|
||||||
open fileprivate(set) var objectEncoding:UInt8 = RTMPConnection.defaultObjectEncoding
|
open fileprivate(set) var objectEncoding:UInt8 = RTMPConnection.defaultObjectEncoding
|
||||||
open fileprivate(set) dynamic var currentFPS:UInt8 = 0
|
open fileprivate(set) dynamic var currentFPS:UInt16 = 0
|
||||||
open var soundTransform:SoundTransform {
|
open var soundTransform:SoundTransform {
|
||||||
get { return audioPlayback.soundTransform }
|
get { return audioPlayback.soundTransform }
|
||||||
set { audioPlayback.soundTransform = newValue }
|
set { audioPlayback.soundTransform = newValue }
|
||||||
|
@ -242,6 +242,7 @@ open class RTMPStream: NetStream {
|
||||||
send(handlerName: "@setDataFrame", arguments: "onMetaData", createMetaData())
|
send(handlerName: "@setDataFrame", arguments: "onMetaData", createMetaData())
|
||||||
mixer.audioIO.encoder.startRunning()
|
mixer.audioIO.encoder.startRunning()
|
||||||
mixer.videoIO.encoder.startRunning()
|
mixer.videoIO.encoder.startRunning()
|
||||||
|
sampler.startRunning()
|
||||||
if (howToPublish == .localRecord) {
|
if (howToPublish == .localRecord) {
|
||||||
mixer.recorder.fileName = info.resourceName
|
mixer.recorder.fileName = info.resourceName
|
||||||
mixer.recorder.startRunning()
|
mixer.recorder.startRunning()
|
||||||
|
@ -256,8 +257,9 @@ open class RTMPStream: NetStream {
|
||||||
var videoTimestamp:Double = 0
|
var videoTimestamp:Double = 0
|
||||||
fileprivate(set) var audioPlayback:RTMPAudioPlayback = RTMPAudioPlayback()
|
fileprivate(set) var audioPlayback:RTMPAudioPlayback = RTMPAudioPlayback()
|
||||||
fileprivate var muxer:RTMPMuxer = RTMPMuxer()
|
fileprivate var muxer:RTMPMuxer = RTMPMuxer()
|
||||||
fileprivate var frameCount:UInt8 = 0
|
fileprivate var sampler:MP4Sampler = MP4Sampler()
|
||||||
fileprivate var chunkTypes:[FLVTag.TagType:Bool] = [:]
|
fileprivate var frameCount:UInt16 = 0
|
||||||
|
fileprivate var chunkTypes:[FLVTagType:Bool] = [:]
|
||||||
fileprivate var dispatcher:IEventDispatcher!
|
fileprivate var dispatcher:IEventDispatcher!
|
||||||
fileprivate var howToPublish:RTMPStream.HowToPublish = .live
|
fileprivate var howToPublish:RTMPStream.HowToPublish = .live
|
||||||
fileprivate var rtmpConnection:RTMPConnection
|
fileprivate var rtmpConnection:RTMPConnection
|
||||||
|
@ -390,6 +392,7 @@ open class RTMPStream: NetStream {
|
||||||
self.mixer.videoIO.encoder.delegate = nil
|
self.mixer.videoIO.encoder.delegate = nil
|
||||||
self.mixer.audioIO.encoder.stopRunning()
|
self.mixer.audioIO.encoder.stopRunning()
|
||||||
self.mixer.videoIO.encoder.stopRunning()
|
self.mixer.videoIO.encoder.stopRunning()
|
||||||
|
self.sampler.stopRunning()
|
||||||
self.mixer.recorder.stopRunning()
|
self.mixer.recorder.stopRunning()
|
||||||
self.FCUnpublish()
|
self.FCUnpublish()
|
||||||
self.rtmpConnection.socket.doOutput(chunk: RTMPChunk(
|
self.rtmpConnection.socket.doOutput(chunk: RTMPChunk(
|
||||||
|
@ -419,6 +422,7 @@ open class RTMPStream: NetStream {
|
||||||
#endif
|
#endif
|
||||||
self.mixer.audioIO.encoder.delegate = self.muxer
|
self.mixer.audioIO.encoder.delegate = self.muxer
|
||||||
self.mixer.videoIO.encoder.delegate = self.muxer
|
self.mixer.videoIO.encoder.delegate = self.muxer
|
||||||
|
self.sampler.delegate = self.muxer
|
||||||
self.mixer.startRunning()
|
self.mixer.startRunning()
|
||||||
self.chunkTypes.removeAll()
|
self.chunkTypes.removeAll()
|
||||||
self.FCPublish()
|
self.FCPublish()
|
||||||
|
@ -491,6 +495,10 @@ open class RTMPStream: NetStream {
|
||||||
return metadata
|
return metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func append(url:URL, completionHandler: MP4Sampler.Handler? = nil) {
|
||||||
|
sampler.append(file: url, completionHandler: completionHandler)
|
||||||
|
}
|
||||||
|
|
||||||
func on(timer:Timer) {
|
func on(timer:Timer) {
|
||||||
currentFPS = frameCount
|
currentFPS = frameCount
|
||||||
frameCount = 0
|
frameCount = 0
|
||||||
|
@ -541,8 +549,8 @@ extension RTMPStream: IEventDispatcher {
|
||||||
public func dispatch(event:Event) {
|
public func dispatch(event:Event) {
|
||||||
dispatcher.dispatch(event: event)
|
dispatcher.dispatch(event: event)
|
||||||
}
|
}
|
||||||
public func dispatch(type:String, bubbles:Bool, data:Any?) {
|
public func dispatch(_ type:String, bubbles:Bool, data:Any?) {
|
||||||
dispatcher.dispatch(type: type, bubbles: bubbles, data: data)
|
dispatcher.dispatch(type, bubbles: bubbles, data: data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,11 +560,11 @@ extension RTMPStream: RTMPMuxerDelegate {
|
||||||
guard readyState == .publishing else {
|
guard readyState == .publishing else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let type:FLVTag.TagType = .audio
|
let type:FLVTagType = .audio
|
||||||
let length:Int = rtmpConnection.socket.doOutput(chunk: RTMPChunk(
|
let length:Int = rtmpConnection.socket.doOutput(chunk: RTMPChunk(
|
||||||
type: chunkTypes[type] == nil ? .zero : .one,
|
type: chunkTypes[type] == nil ? .zero : .one,
|
||||||
streamId: type.streamId,
|
streamId: type.streamId,
|
||||||
message: type.createMessage(id, timestamp: UInt32(audioTimestamp), buffer: buffer)
|
message: type.message(with: id, timestamp: UInt32(audioTimestamp), buffer: buffer)
|
||||||
))
|
))
|
||||||
chunkTypes[type] = true
|
chunkTypes[type] = true
|
||||||
OSAtomicAdd64(Int64(length), &info.byteCount)
|
OSAtomicAdd64(Int64(length), &info.byteCount)
|
||||||
|
@ -567,15 +575,15 @@ extension RTMPStream: RTMPMuxerDelegate {
|
||||||
guard readyState == .publishing else {
|
guard readyState == .publishing else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let type:FLVTag.TagType = .video
|
let type:FLVTagType = .video
|
||||||
let length:Int = rtmpConnection.socket.doOutput(chunk: RTMPChunk(
|
let length:Int = rtmpConnection.socket.doOutput(chunk: RTMPChunk(
|
||||||
type: chunkTypes[type] == nil ? .zero : .one,
|
type: chunkTypes[type] == nil ? .zero : .one,
|
||||||
streamId: type.streamId,
|
streamId: type.streamId,
|
||||||
message: type.createMessage(id, timestamp: UInt32(videoTimestamp), buffer: buffer)
|
message: type.message(with: id, timestamp: UInt32(videoTimestamp), buffer: buffer)
|
||||||
))
|
))
|
||||||
chunkTypes[type] = true
|
chunkTypes[type] = true
|
||||||
OSAtomicAdd64(Int64(length), &info.byteCount)
|
OSAtomicAdd64(Int64(length), &info.byteCount)
|
||||||
videoTimestamp = withTimestamp + (videoTimestamp - floor(videoTimestamp))
|
videoTimestamp = withTimestamp + (videoTimestamp - floor(videoTimestamp))
|
||||||
frameCount = (frameCount + 1) & 0xFF
|
frameCount += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,15 +43,16 @@ final class RTMPTSocket: NSObject, RTMPSocketCompatible {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var delay:UInt8 = 1
|
private var delay:UInt8 = 1
|
||||||
private var mutex:Mutex = Mutex()
|
|
||||||
private var index:Int64 = 0
|
private var index:Int64 = 0
|
||||||
private var events:[Event] = []
|
private var events:[Event] = []
|
||||||
private var baseURL:URL!
|
private var baseURL:URL!
|
||||||
private var session:URLSession!
|
private var session:URLSession!
|
||||||
private var c2packet:[UInt8] = []
|
private var c2packet:[UInt8] = []
|
||||||
private var isPending:Bool = false
|
private var isPending:Bool = false
|
||||||
|
private let outputQueue:DispatchQueue = DispatchQueue(label: "com.github.shgoo4405.lf.RTMPTSocket.output")
|
||||||
private var connectionID:String!
|
private var connectionID:String!
|
||||||
private var outputBuffer:[UInt8] = []
|
private var outputBuffer:[UInt8] = []
|
||||||
|
private var lastResponse:Date = Date()
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
super.init()
|
super.init()
|
||||||
|
@ -77,20 +78,13 @@ final class RTMPTSocket: NSObject, RTMPSocketCompatible {
|
||||||
for chunk in chunks {
|
for chunk in chunks {
|
||||||
bytes.append(contentsOf: chunk)
|
bytes.append(contentsOf: chunk)
|
||||||
}
|
}
|
||||||
do {
|
outputQueue.sync {
|
||||||
try mutex.lock()
|
self.outputBuffer.append(contentsOf: bytes)
|
||||||
outputBuffer.append(contentsOf: bytes)
|
if (!self.isPending) {
|
||||||
if (!isPending) {
|
self.isPending = true
|
||||||
isPending = true
|
self.doOutput(bytes: self.outputBuffer)
|
||||||
doOutput(bytes: outputBuffer)
|
self.outputBuffer.removeAll()
|
||||||
outputBuffer.removeAll()
|
|
||||||
}
|
}
|
||||||
mutex.unlock()
|
|
||||||
} catch {
|
|
||||||
logger.warning("")
|
|
||||||
}
|
|
||||||
if (logger.isEnabledForLogLevel(.verbose)) {
|
|
||||||
logger.verbose("\(chunk)")
|
|
||||||
}
|
}
|
||||||
return bytes.count
|
return bytes.count
|
||||||
}
|
}
|
||||||
|
@ -121,17 +115,14 @@ final class RTMPTSocket: NSObject, RTMPSocketCompatible {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
lastResponse = Date()
|
||||||
try mutex.lock()
|
outputQueue.sync {
|
||||||
if (outputBuffer.isEmpty) {
|
if (self.outputBuffer.isEmpty) {
|
||||||
isPending = false
|
self.isPending = false
|
||||||
} else {
|
} else {
|
||||||
doOutput(bytes: outputBuffer)
|
self.doOutput(bytes: outputBuffer)
|
||||||
outputBuffer.removeAll()
|
self.outputBuffer.removeAll()
|
||||||
}
|
}
|
||||||
mutex.unlock()
|
|
||||||
} catch {
|
|
||||||
logger.warning()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
guard
|
guard
|
||||||
|
|
|
@ -7,7 +7,7 @@ public protocol IEventDispatcher: class {
|
||||||
func addEventListener(_ type:String, selector:Selector, observer:AnyObject?, useCapture:Bool)
|
func addEventListener(_ type:String, selector:Selector, observer:AnyObject?, useCapture:Bool)
|
||||||
func removeEventListener(_ type:String, selector:Selector, observer:AnyObject?, useCapture:Bool)
|
func removeEventListener(_ type:String, selector:Selector, observer:AnyObject?, useCapture:Bool)
|
||||||
func dispatch(event:Event)
|
func dispatch(event:Event)
|
||||||
func dispatch(type:String, bubbles:Bool, data:Any?)
|
func dispatch(_ type:String, bubbles:Bool, data:Any?)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum EventPhase: UInt8 {
|
public enum EventPhase: UInt8 {
|
||||||
|
@ -92,7 +92,7 @@ open class EventDispatcher: NSObject, IEventDispatcher {
|
||||||
event.target = nil
|
event.target = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public final func dispatch(type:String, bubbles:Bool, data:Any?) {
|
public final func dispatch(_ type:String, bubbles:Bool, data:Any?) {
|
||||||
dispatch(event: Event(type: type, bubbles: bubbles, data: data))
|
dispatch(event: Event(type: type, bubbles: bubbles, data: data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
29245AEE1D32347E00AFFB9A /* VideoGravityUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29245AEC1D3233EB00AFFB9A /* VideoGravityUtil.swift */; };
|
29245AEE1D32347E00AFFB9A /* VideoGravityUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29245AEC1D3233EB00AFFB9A /* VideoGravityUtil.swift */; };
|
||||||
29245AEF1D32348400AFFB9A /* VideoGravityUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29245AEC1D3233EB00AFFB9A /* VideoGravityUtil.swift */; };
|
29245AEF1D32348400AFFB9A /* VideoGravityUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29245AEC1D3233EB00AFFB9A /* VideoGravityUtil.swift */; };
|
||||||
292AC17C1CF4C871004F5730 /* MD5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2942424C1CF4C01300D65DCB /* MD5.swift */; };
|
292AC17C1CF4C871004F5730 /* MD5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2942424C1CF4C01300D65DCB /* MD5.swift */; };
|
||||||
|
292D8A331D8B293300DBECE2 /* MP4Sampler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 292D8A321D8B293300DBECE2 /* MP4Sampler.swift */; };
|
||||||
|
292D8A341D8B294900DBECE2 /* MP4Sampler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 292D8A321D8B293300DBECE2 /* MP4Sampler.swift */; };
|
||||||
|
292D8A351D8B294E00DBECE2 /* MP4Reader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29798E511CE5DF1900F5CBD0 /* MP4Reader.swift */; };
|
||||||
2931204C1D4522CF00B14211 /* RTSPRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2931204B1D4522CF00B14211 /* RTSPRequest.swift */; };
|
2931204C1D4522CF00B14211 /* RTSPRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2931204B1D4522CF00B14211 /* RTSPRequest.swift */; };
|
||||||
2931204E1D4522E400B14211 /* RTSPResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2931204D1D4522E400B14211 /* RTSPResponse.swift */; };
|
2931204E1D4522E400B14211 /* RTSPResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2931204D1D4522E400B14211 /* RTSPResponse.swift */; };
|
||||||
2931204F1D4529F900B14211 /* RTSPRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2931204B1D4522CF00B14211 /* RTSPRequest.swift */; };
|
2931204F1D4529F900B14211 /* RTSPRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2931204B1D4522CF00B14211 /* RTSPRequest.swift */; };
|
||||||
|
@ -36,6 +39,11 @@
|
||||||
2942424F1CF4C02300D65DCB /* MD5Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2942424E1CF4C02300D65DCB /* MD5Tests.swift */; };
|
2942424F1CF4C02300D65DCB /* MD5Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2942424E1CF4C02300D65DCB /* MD5Tests.swift */; };
|
||||||
294852571D852499002DE492 /* RTMPTSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294852551D84BFAD002DE492 /* RTMPTSocket.swift */; };
|
294852571D852499002DE492 /* RTMPTSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294852551D84BFAD002DE492 /* RTMPTSocket.swift */; };
|
||||||
2955F51F1D09EBAD004CC995 /* VisualEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296897461CDB01D20074D5F0 /* VisualEffect.swift */; };
|
2955F51F1D09EBAD004CC995 /* VisualEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296897461CDB01D20074D5F0 /* VisualEffect.swift */; };
|
||||||
|
2962425E1D8BFC7B00C451A3 /* MovieClipHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 292D8A301D8B233C00DBECE2 /* MovieClipHandler.swift */; };
|
||||||
|
296242611D8DB86500C451A3 /* TSReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2962425F1D8DB86500C451A3 /* TSReader.swift */; };
|
||||||
|
296242621D8DB86500C451A3 /* TSWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296242601D8DB86500C451A3 /* TSWriter.swift */; };
|
||||||
|
296242631D8DBA8C00C451A3 /* TSReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2962425F1D8DB86500C451A3 /* TSReader.swift */; };
|
||||||
|
296242641D8DBA9000C451A3 /* TSWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296242601D8DB86500C451A3 /* TSWriter.swift */; };
|
||||||
2965434F1D62FAED00734698 /* RTMPConnectionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2965434E1D62FAED00734698 /* RTMPConnectionTests.m */; };
|
2965434F1D62FAED00734698 /* RTMPConnectionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2965434E1D62FAED00734698 /* RTMPConnectionTests.m */; };
|
||||||
296543601D62FE6A00734698 /* AudioUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296543561D62FE6200734698 /* AudioUtil.swift */; };
|
296543601D62FE6A00734698 /* AudioUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296543561D62FE6200734698 /* AudioUtil.swift */; };
|
||||||
296543611D62FE7100734698 /* GLLFView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296543571D62FE6200734698 /* GLLFView.swift */; };
|
296543611D62FE7100734698 /* GLLFView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 296543571D62FE6200734698 /* GLLFView.swift */; };
|
||||||
|
@ -54,7 +62,7 @@
|
||||||
2976A4821D4902CE00B53EF2 /* IOComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2976A4801D49025B00B53EF2 /* IOComponent.swift */; };
|
2976A4821D4902CE00B53EF2 /* IOComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2976A4801D49025B00B53EF2 /* IOComponent.swift */; };
|
||||||
2976A4861D4903C300B53EF2 /* DeviceUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2976A4851D4903C300B53EF2 /* DeviceUtil.swift */; };
|
2976A4861D4903C300B53EF2 /* DeviceUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2976A4851D4903C300B53EF2 /* DeviceUtil.swift */; };
|
||||||
2976A4871D49045700B53EF2 /* DeviceUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2976A4851D4903C300B53EF2 /* DeviceUtil.swift */; };
|
2976A4871D49045700B53EF2 /* DeviceUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2976A4851D4903C300B53EF2 /* DeviceUtil.swift */; };
|
||||||
29798E521CE5DF1A00F5CBD0 /* MP4File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29798E511CE5DF1900F5CBD0 /* MP4File.swift */; };
|
29798E521CE5DF1A00F5CBD0 /* MP4Reader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29798E511CE5DF1900F5CBD0 /* MP4Reader.swift */; };
|
||||||
29798E671CE610F500F5CBD0 /* lf.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B8761B1CD701F900FC07DA /* lf.framework */; };
|
29798E671CE610F500F5CBD0 /* lf.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B8761B1CD701F900FC07DA /* lf.framework */; };
|
||||||
29798E691CE6110F00F5CBD0 /* ASClassTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876CE1CD70CE700FC07DA /* ASClassTests.swift */; };
|
29798E691CE6110F00F5CBD0 /* ASClassTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876CE1CD70CE700FC07DA /* ASClassTests.swift */; };
|
||||||
29798E6A1CE6110F00F5CBD0 /* ByteArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876CF1CD70CE700FC07DA /* ByteArrayTests.swift */; };
|
29798E6A1CE6110F00F5CBD0 /* ByteArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876CF1CD70CE700FC07DA /* ByteArrayTests.swift */; };
|
||||||
|
@ -81,7 +89,6 @@
|
||||||
299B131D1D35272D00A1E8F5 /* ScreenCaptureSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 299B131C1D35272D00A1E8F5 /* ScreenCaptureSession.swift */; };
|
299B131D1D35272D00A1E8F5 /* ScreenCaptureSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 299B131C1D35272D00A1E8F5 /* ScreenCaptureSession.swift */; };
|
||||||
299B13271D3B751400A1E8F5 /* LFView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 299B13261D3B751400A1E8F5 /* LFView.swift */; };
|
299B13271D3B751400A1E8F5 /* LFView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 299B13261D3B751400A1E8F5 /* LFView.swift */; };
|
||||||
29A39C8E1D85BF6F007C27E9 /* BroadcastViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A39C831D85BF21007C27E9 /* BroadcastViewController.swift */; };
|
29A39C8E1D85BF6F007C27E9 /* BroadcastViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A39C831D85BF21007C27E9 /* BroadcastViewController.swift */; };
|
||||||
29A39C901D85BF9C007C27E9 /* SampleHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A39C8A1D85BF30007C27E9 /* SampleHandler.swift */; };
|
|
||||||
29A39C921D85CF5F007C27E9 /* RTMPSampleHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A39C911D85CF5E007C27E9 /* RTMPSampleHandler.swift */; };
|
29A39C921D85CF5F007C27E9 /* RTMPSampleHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A39C911D85CF5E007C27E9 /* RTMPSampleHandler.swift */; };
|
||||||
29AF3FCF1D7C744C00E41212 /* NetStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29AF3FCE1D7C744C00E41212 /* NetStream.swift */; };
|
29AF3FCF1D7C744C00E41212 /* NetStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29AF3FCE1D7C744C00E41212 /* NetStream.swift */; };
|
||||||
29AF3FD01D7C745200E41212 /* NetStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29AF3FCE1D7C744C00E41212 /* NetStream.swift */; };
|
29AF3FD01D7C745200E41212 /* NetStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29AF3FCE1D7C744C00E41212 /* NetStream.swift */; };
|
||||||
|
@ -98,8 +105,6 @@
|
||||||
29B876781CD70ACE00FC07DA /* HTTPService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876711CD70ACE00FC07DA /* HTTPService.swift */; };
|
29B876781CD70ACE00FC07DA /* HTTPService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876711CD70ACE00FC07DA /* HTTPService.swift */; };
|
||||||
29B876791CD70ACE00FC07DA /* HTTPStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876721CD70ACE00FC07DA /* HTTPStream.swift */; };
|
29B876791CD70ACE00FC07DA /* HTTPStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876721CD70ACE00FC07DA /* HTTPStream.swift */; };
|
||||||
29B8767A1CD70ACE00FC07DA /* M3U.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876731CD70ACE00FC07DA /* M3U.swift */; };
|
29B8767A1CD70ACE00FC07DA /* M3U.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876731CD70ACE00FC07DA /* M3U.swift */; };
|
||||||
29B8767B1CD70ACE00FC07DA /* TSReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876741CD70ACE00FC07DA /* TSReader.swift */; };
|
|
||||||
29B8767C1CD70ACE00FC07DA /* TSWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876751CD70ACE00FC07DA /* TSWriter.swift */; };
|
|
||||||
29B876831CD70AE800FC07DA /* AudioSpecificConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B8767D1CD70AE800FC07DA /* AudioSpecificConfig.swift */; };
|
29B876831CD70AE800FC07DA /* AudioSpecificConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B8767D1CD70AE800FC07DA /* AudioSpecificConfig.swift */; };
|
||||||
29B876841CD70AE800FC07DA /* H264+AVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B8767E1CD70AE800FC07DA /* H264+AVC.swift */; };
|
29B876841CD70AE800FC07DA /* H264+AVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B8767E1CD70AE800FC07DA /* H264+AVC.swift */; };
|
||||||
29B876851CD70AE800FC07DA /* NALUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B8767F1CD70AE800FC07DA /* NALUnit.swift */; };
|
29B876851CD70AE800FC07DA /* NALUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B8767F1CD70AE800FC07DA /* NALUnit.swift */; };
|
||||||
|
@ -143,8 +148,6 @@
|
||||||
29B876F81CD70D5900FC07DA /* HTTPService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876711CD70ACE00FC07DA /* HTTPService.swift */; };
|
29B876F81CD70D5900FC07DA /* HTTPService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876711CD70ACE00FC07DA /* HTTPService.swift */; };
|
||||||
29B876F91CD70D5900FC07DA /* HTTPStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876721CD70ACE00FC07DA /* HTTPStream.swift */; };
|
29B876F91CD70D5900FC07DA /* HTTPStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876721CD70ACE00FC07DA /* HTTPStream.swift */; };
|
||||||
29B876FA1CD70D5900FC07DA /* M3U.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876731CD70ACE00FC07DA /* M3U.swift */; };
|
29B876FA1CD70D5900FC07DA /* M3U.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876731CD70ACE00FC07DA /* M3U.swift */; };
|
||||||
29B876FB1CD70D5A00FC07DA /* TSReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876741CD70ACE00FC07DA /* TSReader.swift */; };
|
|
||||||
29B876FC1CD70D5A00FC07DA /* TSWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B876751CD70ACE00FC07DA /* TSWriter.swift */; };
|
|
||||||
29B876FD1CD70D5A00FC07DA /* AudioSpecificConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B8767D1CD70AE800FC07DA /* AudioSpecificConfig.swift */; };
|
29B876FD1CD70D5A00FC07DA /* AudioSpecificConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B8767D1CD70AE800FC07DA /* AudioSpecificConfig.swift */; };
|
||||||
29B876FE1CD70D5A00FC07DA /* H264+AVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B8767E1CD70AE800FC07DA /* H264+AVC.swift */; };
|
29B876FE1CD70D5A00FC07DA /* H264+AVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B8767E1CD70AE800FC07DA /* H264+AVC.swift */; };
|
||||||
29B876FF1CD70D5A00FC07DA /* NALUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B8767F1CD70AE800FC07DA /* NALUnit.swift */; };
|
29B876FF1CD70D5A00FC07DA /* NALUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B8767F1CD70AE800FC07DA /* NALUnit.swift */; };
|
||||||
|
@ -282,6 +285,8 @@
|
||||||
291F4E361CF206E200F59C51 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon.png; path = Examples/iOS/Icon.png; sourceTree = "<group>"; };
|
291F4E361CF206E200F59C51 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon.png; path = Examples/iOS/Icon.png; sourceTree = "<group>"; };
|
||||||
2923A1FA1D63011E0019FBCD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Examples/macOS/Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
2923A1FA1D63011E0019FBCD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Examples/macOS/Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||||
29245AEC1D3233EB00AFFB9A /* VideoGravityUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VideoGravityUtil.swift; path = Sources/Util/VideoGravityUtil.swift; sourceTree = SOURCE_ROOT; };
|
29245AEC1D3233EB00AFFB9A /* VideoGravityUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = VideoGravityUtil.swift; path = Sources/Util/VideoGravityUtil.swift; sourceTree = SOURCE_ROOT; };
|
||||||
|
292D8A301D8B233C00DBECE2 /* MovieClipHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MovieClipHandler.swift; path = Examples/iOS/Screencast/MovieClipHandler.swift; sourceTree = "<group>"; };
|
||||||
|
292D8A321D8B293300DBECE2 /* MP4Sampler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MP4Sampler.swift; path = Sources/ISO/MP4Sampler.swift; sourceTree = SOURCE_ROOT; };
|
||||||
2931204B1D4522CF00B14211 /* RTSPRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RTSPRequest.swift; path = Sources/RTSP/RTSPRequest.swift; sourceTree = SOURCE_ROOT; };
|
2931204B1D4522CF00B14211 /* RTSPRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RTSPRequest.swift; path = Sources/RTSP/RTSPRequest.swift; sourceTree = SOURCE_ROOT; };
|
||||||
2931204D1D4522E400B14211 /* RTSPResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RTSPResponse.swift; path = Sources/RTSP/RTSPResponse.swift; sourceTree = SOURCE_ROOT; };
|
2931204D1D4522E400B14211 /* RTSPResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RTSPResponse.swift; path = Sources/RTSP/RTSPResponse.swift; sourceTree = SOURCE_ROOT; };
|
||||||
293C74361D85D56D001ED43C /* MainInterface.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = MainInterface.storyboard; path = Examples/iOS/ScreencastUI/Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
293C74361D85D56D001ED43C /* MainInterface.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = MainInterface.storyboard; path = Examples/iOS/ScreencastUI/Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
||||||
|
@ -289,6 +294,8 @@
|
||||||
2942424E1CF4C02300D65DCB /* MD5Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MD5Tests.swift; sourceTree = "<group>"; };
|
2942424E1CF4C02300D65DCB /* MD5Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MD5Tests.swift; sourceTree = "<group>"; };
|
||||||
2945CBBD1B4BE66000104112 /* lf.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = lf.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
2945CBBD1B4BE66000104112 /* lf.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = lf.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
294852551D84BFAD002DE492 /* RTMPTSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RTMPTSocket.swift; path = Sources/RTMP/RTMPTSocket.swift; sourceTree = SOURCE_ROOT; };
|
294852551D84BFAD002DE492 /* RTMPTSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RTMPTSocket.swift; path = Sources/RTMP/RTMPTSocket.swift; sourceTree = SOURCE_ROOT; };
|
||||||
|
2962425F1D8DB86500C451A3 /* TSReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TSReader.swift; path = Sources/ISO/TSReader.swift; sourceTree = SOURCE_ROOT; };
|
||||||
|
296242601D8DB86500C451A3 /* TSWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TSWriter.swift; path = Sources/ISO/TSWriter.swift; sourceTree = SOURCE_ROOT; };
|
||||||
2965434E1D62FAED00734698 /* RTMPConnectionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RTMPConnectionTests.m; sourceTree = "<group>"; };
|
2965434E1D62FAED00734698 /* RTMPConnectionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RTMPConnectionTests.m; sourceTree = "<group>"; };
|
||||||
296543561D62FE6200734698 /* AudioUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AudioUtil.swift; path = Platforms/macOS/AudioUtil.swift; sourceTree = "<group>"; };
|
296543561D62FE6200734698 /* AudioUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AudioUtil.swift; path = Platforms/macOS/AudioUtil.swift; sourceTree = "<group>"; };
|
||||||
296543571D62FE6200734698 /* GLLFView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GLLFView.swift; path = Platforms/macOS/GLLFView.swift; sourceTree = "<group>"; };
|
296543571D62FE6200734698 /* GLLFView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GLLFView.swift; path = Platforms/macOS/GLLFView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -312,7 +319,7 @@
|
||||||
2976A47D1D48C5C700B53EF2 /* AVMixerRecorder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AVMixerRecorder.swift; path = Sources/Media/AVMixerRecorder.swift; sourceTree = SOURCE_ROOT; };
|
2976A47D1D48C5C700B53EF2 /* AVMixerRecorder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AVMixerRecorder.swift; path = Sources/Media/AVMixerRecorder.swift; sourceTree = SOURCE_ROOT; };
|
||||||
2976A4801D49025B00B53EF2 /* IOComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = IOComponent.swift; path = Sources/Media/IOComponent.swift; sourceTree = SOURCE_ROOT; };
|
2976A4801D49025B00B53EF2 /* IOComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = IOComponent.swift; path = Sources/Media/IOComponent.swift; sourceTree = SOURCE_ROOT; };
|
||||||
2976A4851D4903C300B53EF2 /* DeviceUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeviceUtil.swift; path = Sources/Util/DeviceUtil.swift; sourceTree = SOURCE_ROOT; };
|
2976A4851D4903C300B53EF2 /* DeviceUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeviceUtil.swift; path = Sources/Util/DeviceUtil.swift; sourceTree = SOURCE_ROOT; };
|
||||||
29798E511CE5DF1900F5CBD0 /* MP4File.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MP4File.swift; path = Sources/ISO/MP4File.swift; sourceTree = SOURCE_ROOT; };
|
29798E511CE5DF1900F5CBD0 /* MP4Reader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MP4Reader.swift; path = Sources/ISO/MP4Reader.swift; sourceTree = SOURCE_ROOT; };
|
||||||
29798E591CE60E5300F5CBD0 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
29798E591CE60E5300F5CBD0 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
29798E5D1CE60E5300F5CBD0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
29798E5D1CE60E5300F5CBD0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
2981B7F31D7345D5002FA821 /* SessionDescription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SessionDescription.swift; path = Sources/RTSP/SessionDescription.swift; sourceTree = SOURCE_ROOT; };
|
2981B7F31D7345D5002FA821 /* SessionDescription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SessionDescription.swift; path = Sources/RTSP/SessionDescription.swift; sourceTree = SOURCE_ROOT; };
|
||||||
|
@ -331,7 +338,6 @@
|
||||||
29A39C831D85BF21007C27E9 /* BroadcastViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BroadcastViewController.swift; path = Examples/iOS/ScreencastUI/BroadcastViewController.swift; sourceTree = "<group>"; };
|
29A39C831D85BF21007C27E9 /* BroadcastViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BroadcastViewController.swift; path = Examples/iOS/ScreencastUI/BroadcastViewController.swift; sourceTree = "<group>"; };
|
||||||
29A39C841D85BF21007C27E9 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Examples/iOS/ScreencastUI/Info.plist; sourceTree = "<group>"; };
|
29A39C841D85BF21007C27E9 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Examples/iOS/ScreencastUI/Info.plist; sourceTree = "<group>"; };
|
||||||
29A39C881D85BF30007C27E9 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Examples/iOS/Screencast/Info.plist; sourceTree = "<group>"; };
|
29A39C881D85BF30007C27E9 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Examples/iOS/Screencast/Info.plist; sourceTree = "<group>"; };
|
||||||
29A39C8A1D85BF30007C27E9 /* SampleHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SampleHandler.swift; path = Examples/iOS/Screencast/SampleHandler.swift; sourceTree = "<group>"; };
|
|
||||||
29A39C911D85CF5E007C27E9 /* RTMPSampleHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RTMPSampleHandler.swift; path = Platforms/iOS/RTMPSampleHandler.swift; sourceTree = "<group>"; };
|
29A39C911D85CF5E007C27E9 /* RTMPSampleHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RTMPSampleHandler.swift; path = Platforms/iOS/RTMPSampleHandler.swift; sourceTree = "<group>"; };
|
||||||
29AF3FCE1D7C744C00E41212 /* NetStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NetStream.swift; path = Sources/Net/NetStream.swift; sourceTree = SOURCE_ROOT; };
|
29AF3FCE1D7C744C00E41212 /* NetStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NetStream.swift; path = Sources/Net/NetStream.swift; sourceTree = SOURCE_ROOT; };
|
||||||
29B8761B1CD701F900FC07DA /* lf.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = lf.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
29B8761B1CD701F900FC07DA /* lf.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = lf.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
@ -348,8 +354,6 @@
|
||||||
29B876711CD70ACE00FC07DA /* HTTPService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPService.swift; path = Sources/HTTP/HTTPService.swift; sourceTree = SOURCE_ROOT; };
|
29B876711CD70ACE00FC07DA /* HTTPService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPService.swift; path = Sources/HTTP/HTTPService.swift; sourceTree = SOURCE_ROOT; };
|
||||||
29B876721CD70ACE00FC07DA /* HTTPStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPStream.swift; path = Sources/HTTP/HTTPStream.swift; sourceTree = SOURCE_ROOT; };
|
29B876721CD70ACE00FC07DA /* HTTPStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPStream.swift; path = Sources/HTTP/HTTPStream.swift; sourceTree = SOURCE_ROOT; };
|
||||||
29B876731CD70ACE00FC07DA /* M3U.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = M3U.swift; path = Sources/HTTP/M3U.swift; sourceTree = SOURCE_ROOT; };
|
29B876731CD70ACE00FC07DA /* M3U.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = M3U.swift; path = Sources/HTTP/M3U.swift; sourceTree = SOURCE_ROOT; };
|
||||||
29B876741CD70ACE00FC07DA /* TSReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TSReader.swift; path = Sources/HTTP/TSReader.swift; sourceTree = SOURCE_ROOT; };
|
|
||||||
29B876751CD70ACE00FC07DA /* TSWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TSWriter.swift; path = Sources/HTTP/TSWriter.swift; sourceTree = SOURCE_ROOT; };
|
|
||||||
29B8767D1CD70AE800FC07DA /* AudioSpecificConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AudioSpecificConfig.swift; path = Sources/ISO/AudioSpecificConfig.swift; sourceTree = SOURCE_ROOT; };
|
29B8767D1CD70AE800FC07DA /* AudioSpecificConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AudioSpecificConfig.swift; path = Sources/ISO/AudioSpecificConfig.swift; sourceTree = SOURCE_ROOT; };
|
||||||
29B8767E1CD70AE800FC07DA /* H264+AVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "H264+AVC.swift"; path = "Sources/ISO/H264+AVC.swift"; sourceTree = SOURCE_ROOT; };
|
29B8767E1CD70AE800FC07DA /* H264+AVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "H264+AVC.swift"; path = "Sources/ISO/H264+AVC.swift"; sourceTree = SOURCE_ROOT; };
|
||||||
29B8767F1CD70AE800FC07DA /* NALUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NALUnit.swift; path = Sources/ISO/NALUnit.swift; sourceTree = SOURCE_ROOT; };
|
29B8767F1CD70AE800FC07DA /* NALUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NALUnit.swift; path = Sources/ISO/NALUnit.swift; sourceTree = SOURCE_ROOT; };
|
||||||
|
@ -666,11 +670,14 @@
|
||||||
children = (
|
children = (
|
||||||
29B8767D1CD70AE800FC07DA /* AudioSpecificConfig.swift */,
|
29B8767D1CD70AE800FC07DA /* AudioSpecificConfig.swift */,
|
||||||
29B8767E1CD70AE800FC07DA /* H264+AVC.swift */,
|
29B8767E1CD70AE800FC07DA /* H264+AVC.swift */,
|
||||||
29798E511CE5DF1900F5CBD0 /* MP4File.swift */,
|
29798E511CE5DF1900F5CBD0 /* MP4Reader.swift */,
|
||||||
|
292D8A321D8B293300DBECE2 /* MP4Sampler.swift */,
|
||||||
29B8767F1CD70AE800FC07DA /* NALUnit.swift */,
|
29B8767F1CD70AE800FC07DA /* NALUnit.swift */,
|
||||||
29B876801CD70AE800FC07DA /* PacketizedElementaryStream.swift */,
|
29B876801CD70AE800FC07DA /* PacketizedElementaryStream.swift */,
|
||||||
29B876811CD70AE800FC07DA /* ProgramSpecific.swift */,
|
29B876811CD70AE800FC07DA /* ProgramSpecific.swift */,
|
||||||
29B876821CD70AE800FC07DA /* TransportStream.swift */,
|
29B876821CD70AE800FC07DA /* TransportStream.swift */,
|
||||||
|
2962425F1D8DB86500C451A3 /* TSReader.swift */,
|
||||||
|
296242601D8DB86500C451A3 /* TSWriter.swift */,
|
||||||
);
|
);
|
||||||
name = ISO;
|
name = ISO;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -683,8 +690,6 @@
|
||||||
29B876711CD70ACE00FC07DA /* HTTPService.swift */,
|
29B876711CD70ACE00FC07DA /* HTTPService.swift */,
|
||||||
29B876721CD70ACE00FC07DA /* HTTPStream.swift */,
|
29B876721CD70ACE00FC07DA /* HTTPStream.swift */,
|
||||||
29B876731CD70ACE00FC07DA /* M3U.swift */,
|
29B876731CD70ACE00FC07DA /* M3U.swift */,
|
||||||
29B876741CD70ACE00FC07DA /* TSReader.swift */,
|
|
||||||
29B876751CD70ACE00FC07DA /* TSWriter.swift */,
|
|
||||||
);
|
);
|
||||||
name = HTTP;
|
name = HTTP;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -823,7 +828,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
29A39C881D85BF30007C27E9 /* Info.plist */,
|
29A39C881D85BF30007C27E9 /* Info.plist */,
|
||||||
29A39C8A1D85BF30007C27E9 /* SampleHandler.swift */,
|
292D8A301D8B233C00DBECE2 /* MovieClipHandler.swift */,
|
||||||
);
|
);
|
||||||
name = Screencast;
|
name = Screencast;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -1485,7 +1490,7 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
29A39C901D85BF9C007C27E9 /* SampleHandler.swift in Sources */,
|
2962425E1D8BFC7B00C451A3 /* MovieClipHandler.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -1511,7 +1516,6 @@
|
||||||
29B8766E1CD70AB300FC07DA /* SiwftCore+Extension.swift in Sources */,
|
29B8766E1CD70AB300FC07DA /* SiwftCore+Extension.swift in Sources */,
|
||||||
2901A4EE1D437170002BBD23 /* ClockedQueue.swift in Sources */,
|
2901A4EE1D437170002BBD23 /* ClockedQueue.swift in Sources */,
|
||||||
29B876941CD70AFE00FC07DA /* SoundTransform.swift in Sources */,
|
29B876941CD70AFE00FC07DA /* SoundTransform.swift in Sources */,
|
||||||
29B8767B1CD70ACE00FC07DA /* TSReader.swift in Sources */,
|
|
||||||
2931204C1D4522CF00B14211 /* RTSPRequest.swift in Sources */,
|
2931204C1D4522CF00B14211 /* RTSPRequest.swift in Sources */,
|
||||||
29B876861CD70AE800FC07DA /* PacketizedElementaryStream.swift in Sources */,
|
29B876861CD70AE800FC07DA /* PacketizedElementaryStream.swift in Sources */,
|
||||||
29B876761CD70ACE00FC07DA /* HTTPRequest.swift in Sources */,
|
29B876761CD70ACE00FC07DA /* HTTPRequest.swift in Sources */,
|
||||||
|
@ -1519,6 +1523,7 @@
|
||||||
299AE0E51D44EC7800D26A49 /* RTSPSocket.swift in Sources */,
|
299AE0E51D44EC7800D26A49 /* RTSPSocket.swift in Sources */,
|
||||||
29DD70E61D68CF020021904A /* RTPPacket.swift in Sources */,
|
29DD70E61D68CF020021904A /* RTPPacket.swift in Sources */,
|
||||||
29B876AD1CD70B2800FC07DA /* ASClass.swift in Sources */,
|
29B876AD1CD70B2800FC07DA /* ASClass.swift in Sources */,
|
||||||
|
296242611D8DB86500C451A3 /* TSReader.swift in Sources */,
|
||||||
29B8766B1CD70AB300FC07DA /* Foundation+Extension.swift in Sources */,
|
29B8766B1CD70AB300FC07DA /* Foundation+Extension.swift in Sources */,
|
||||||
2981B7F41D7345D5002FA821 /* SessionDescription.swift in Sources */,
|
2981B7F41D7345D5002FA821 /* SessionDescription.swift in Sources */,
|
||||||
2931204E1D4522E400B14211 /* RTSPResponse.swift in Sources */,
|
2931204E1D4522E400B14211 /* RTSPResponse.swift in Sources */,
|
||||||
|
@ -1529,10 +1534,10 @@
|
||||||
299B13271D3B751400A1E8F5 /* LFView.swift in Sources */,
|
299B13271D3B751400A1E8F5 /* LFView.swift in Sources */,
|
||||||
29B876AF1CD70B2800FC07DA /* RTMPChunk.swift in Sources */,
|
29B876AF1CD70B2800FC07DA /* RTMPChunk.swift in Sources */,
|
||||||
29B876841CD70AE800FC07DA /* H264+AVC.swift in Sources */,
|
29B876841CD70AE800FC07DA /* H264+AVC.swift in Sources */,
|
||||||
|
296242621D8DB86500C451A3 /* TSWriter.swift in Sources */,
|
||||||
29B8769B1CD70B1100FC07DA /* MIME.swift in Sources */,
|
29B8769B1CD70B1100FC07DA /* MIME.swift in Sources */,
|
||||||
29A39C921D85CF5F007C27E9 /* RTMPSampleHandler.swift in Sources */,
|
29A39C921D85CF5F007C27E9 /* RTMPSampleHandler.swift in Sources */,
|
||||||
29B8769C1CD70B1100FC07DA /* NetClient.swift in Sources */,
|
29B8769C1CD70B1100FC07DA /* NetClient.swift in Sources */,
|
||||||
29B8767C1CD70ACE00FC07DA /* TSWriter.swift in Sources */,
|
|
||||||
29B876871CD70AE800FC07DA /* ProgramSpecific.swift in Sources */,
|
29B876871CD70AE800FC07DA /* ProgramSpecific.swift in Sources */,
|
||||||
29B876B01CD70B2800FC07DA /* RTMPConnection.swift in Sources */,
|
29B876B01CD70B2800FC07DA /* RTMPConnection.swift in Sources */,
|
||||||
29B876B61CD70B2800FC07DA /* RTMPStream.swift in Sources */,
|
29B876B61CD70B2800FC07DA /* RTMPStream.swift in Sources */,
|
||||||
|
@ -1558,7 +1563,8 @@
|
||||||
29B8769D1CD70B1100FC07DA /* NetService.swift in Sources */,
|
29B8769D1CD70B1100FC07DA /* NetService.swift in Sources */,
|
||||||
29B8769E1CD70B1100FC07DA /* NetSocket.swift in Sources */,
|
29B8769E1CD70B1100FC07DA /* NetSocket.swift in Sources */,
|
||||||
29B876791CD70ACE00FC07DA /* HTTPStream.swift in Sources */,
|
29B876791CD70ACE00FC07DA /* HTTPStream.swift in Sources */,
|
||||||
29798E521CE5DF1A00F5CBD0 /* MP4File.swift in Sources */,
|
292D8A331D8B293300DBECE2 /* MP4Sampler.swift in Sources */,
|
||||||
|
29798E521CE5DF1A00F5CBD0 /* MP4Reader.swift in Sources */,
|
||||||
29B876AC1CD70B2800FC07DA /* AMF3Serializer.swift in Sources */,
|
29B876AC1CD70B2800FC07DA /* AMF3Serializer.swift in Sources */,
|
||||||
29B876921CD70AFE00FC07DA /* AVMixer.swift in Sources */,
|
29B876921CD70AFE00FC07DA /* AVMixer.swift in Sources */,
|
||||||
29B876911CD70AFE00FC07DA /* AudioStreamPlayback.swift in Sources */,
|
29B876911CD70AFE00FC07DA /* AudioStreamPlayback.swift in Sources */,
|
||||||
|
@ -1616,16 +1622,18 @@
|
||||||
29B876F91CD70D5900FC07DA /* HTTPStream.swift in Sources */,
|
29B876F91CD70D5900FC07DA /* HTTPStream.swift in Sources */,
|
||||||
296543631D62FE9000734698 /* LFView.swift in Sources */,
|
296543631D62FE9000734698 /* LFView.swift in Sources */,
|
||||||
29B876FA1CD70D5900FC07DA /* M3U.swift in Sources */,
|
29B876FA1CD70D5900FC07DA /* M3U.swift in Sources */,
|
||||||
29B876FB1CD70D5A00FC07DA /* TSReader.swift in Sources */,
|
292D8A341D8B294900DBECE2 /* MP4Sampler.swift in Sources */,
|
||||||
29B876FC1CD70D5A00FC07DA /* TSWriter.swift in Sources */,
|
|
||||||
29B876FD1CD70D5A00FC07DA /* AudioSpecificConfig.swift in Sources */,
|
29B876FD1CD70D5A00FC07DA /* AudioSpecificConfig.swift in Sources */,
|
||||||
|
296242631D8DBA8C00C451A3 /* TSReader.swift in Sources */,
|
||||||
29B876FE1CD70D5A00FC07DA /* H264+AVC.swift in Sources */,
|
29B876FE1CD70D5A00FC07DA /* H264+AVC.swift in Sources */,
|
||||||
294852571D852499002DE492 /* RTMPTSocket.swift in Sources */,
|
294852571D852499002DE492 /* RTMPTSocket.swift in Sources */,
|
||||||
29245AEE1D32347E00AFFB9A /* VideoGravityUtil.swift in Sources */,
|
29245AEE1D32347E00AFFB9A /* VideoGravityUtil.swift in Sources */,
|
||||||
|
292D8A351D8B294E00DBECE2 /* MP4Reader.swift in Sources */,
|
||||||
29B876FF1CD70D5A00FC07DA /* NALUnit.swift in Sources */,
|
29B876FF1CD70D5A00FC07DA /* NALUnit.swift in Sources */,
|
||||||
29B877001CD70D5A00FC07DA /* PacketizedElementaryStream.swift in Sources */,
|
29B877001CD70D5A00FC07DA /* PacketizedElementaryStream.swift in Sources */,
|
||||||
29B877011CD70D5A00FC07DA /* ProgramSpecific.swift in Sources */,
|
29B877011CD70D5A00FC07DA /* ProgramSpecific.swift in Sources */,
|
||||||
29B877021CD70D5A00FC07DA /* TransportStream.swift in Sources */,
|
29B877021CD70D5A00FC07DA /* TransportStream.swift in Sources */,
|
||||||
|
296242641D8DBA9000C451A3 /* TSWriter.swift in Sources */,
|
||||||
29B877031CD70D5A00FC07DA /* AudioIOComponent.swift in Sources */,
|
29B877031CD70D5A00FC07DA /* AudioIOComponent.swift in Sources */,
|
||||||
29B877041CD70D5A00FC07DA /* AudioStreamPlayback.swift in Sources */,
|
29B877041CD70D5A00FC07DA /* AudioStreamPlayback.swift in Sources */,
|
||||||
2931204F1D4529F900B14211 /* RTSPRequest.swift in Sources */,
|
2931204F1D4529F900B14211 /* RTSPRequest.swift in Sources */,
|
||||||
|
|
Loading…
Reference in New Issue