Skip to content

Commit

Permalink
refs #1603
Browse files Browse the repository at this point in the history
  • Loading branch information
shogo4405 committed Oct 14, 2024
1 parent eae1ed0 commit f1074c6
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 45 deletions.
2 changes: 1 addition & 1 deletion Sources/Codec/VideoCodec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ final class VideoCodec<T: VideoCodecDelegate> {
guard kVideoCodec_defaultFrameInterval < frameInterval else {
return true
}
return frameInterval < presentationTimeStamp.seconds - self.presentationTimeStamp.seconds
return frameInterval <= presentationTimeStamp.seconds - self.presentationTimeStamp.seconds
}

#if os(iOS) || os(tvOS) || os(visionOS)
Expand Down
76 changes: 42 additions & 34 deletions Sources/RTMP/RTMPMuxer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,46 +153,54 @@ extension RTMPMuxer: IOMuxer {
guard let stream, let audioBuffer = audioBuffer as? AVAudioCompressedBuffer else {
return
}
let timedelta = audioTimestamp.update(when)
var buffer = Data([RTMPMuxer.aac, FLVAACPacketType.raw.rawValue])
buffer.append(audioBuffer.data.assumingMemoryBound(to: UInt8.self), count: Int(audioBuffer.byteLength))
stream.doOutput(
.one,
chunkStreamId: FLVTagType.audio.streamId,
message: RTMPAudioMessage(streamId: 0, timestamp: timedelta, payload: buffer)
)
do {
let timedelta = try audioTimestamp.update(when)
var buffer = Data([RTMPMuxer.aac, FLVAACPacketType.raw.rawValue])
buffer.append(audioBuffer.data.assumingMemoryBound(to: UInt8.self), count: Int(audioBuffer.byteLength))
stream.doOutput(
.one,
chunkStreamId: FLVTagType.audio.streamId,
message: RTMPAudioMessage(streamId: 0, timestamp: timedelta, payload: buffer)
)
} catch {
logger.info(error)
}
}

func append(_ sampleBuffer: CMSampleBuffer) {
guard let stream, let data = try? sampleBuffer.dataBuffer?.dataBytes() else {
return
}
let keyframe = !sampleBuffer.isNotSync
let decodeTimeStamp = sampleBuffer.decodeTimeStamp.isValid ? sampleBuffer.decodeTimeStamp : sampleBuffer.presentationTimeStamp
let compositionTime = videoTimestamp.getCompositionTime(sampleBuffer)
let timedelta = videoTimestamp.update(decodeTimeStamp)
stream.frameCount += 1
switch sampleBuffer.formatDescription?.mediaSubType {
case .h264?:
var buffer = Data([((keyframe ? FLVFrameType.key.rawValue : FLVFrameType.inter.rawValue) << 4) | FLVVideoCodec.avc.rawValue, FLVAVCPacketType.nal.rawValue])
buffer.append(contentsOf: compositionTime.bigEndian.data[1..<4])
buffer.append(data)
stream.doOutput(
.one,
chunkStreamId: FLVTagType.video.streamId,
message: RTMPVideoMessage(streamId: 0, timestamp: timedelta, payload: buffer)
)
case .hevc?:
var buffer = Data([0b10000000 | ((keyframe ? FLVFrameType.key.rawValue : FLVFrameType.inter.rawValue) << 4) | FLVVideoPacketType.codedFrames.rawValue, 0x68, 0x76, 0x63, 0x31])
buffer.append(contentsOf: compositionTime.bigEndian.data[1..<4])
buffer.append(data)
stream.doOutput(
.one,
chunkStreamId: FLVTagType.video.streamId,
message: RTMPVideoMessage(streamId: 0, timestamp: timedelta, payload: buffer)
)
default:
break
do {
let keyframe = !sampleBuffer.isNotSync
let decodeTimeStamp = sampleBuffer.decodeTimeStamp.isValid ? sampleBuffer.decodeTimeStamp : sampleBuffer.presentationTimeStamp
let compositionTime = videoTimestamp.getCompositionTime(sampleBuffer)
let timedelta = try videoTimestamp.update(decodeTimeStamp)
stream.frameCount += 1
switch sampleBuffer.formatDescription?.mediaSubType {
case .h264?:
var buffer = Data([((keyframe ? FLVFrameType.key.rawValue : FLVFrameType.inter.rawValue) << 4) | FLVVideoCodec.avc.rawValue, FLVAVCPacketType.nal.rawValue])
buffer.append(contentsOf: compositionTime.bigEndian.data[1..<4])
buffer.append(data)
stream.doOutput(
.one,
chunkStreamId: FLVTagType.video.streamId,
message: RTMPVideoMessage(streamId: 0, timestamp: timedelta, payload: buffer)
)
case .hevc?:
var buffer = Data([0b10000000 | ((keyframe ? FLVFrameType.key.rawValue : FLVFrameType.inter.rawValue) << 4) | FLVVideoPacketType.codedFrames.rawValue, 0x68, 0x76, 0x63, 0x31])
buffer.append(contentsOf: compositionTime.bigEndian.data[1..<4])
buffer.append(data)
stream.doOutput(
.one,
chunkStreamId: FLVTagType.video.streamId,
message: RTMPVideoMessage(streamId: 0, timestamp: timedelta, payload: buffer)
)
default:
break
}
} catch {
logger.info(error)
}
}
}
Expand Down
26 changes: 16 additions & 10 deletions Sources/RTMP/RTMPTimestamp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,31 @@ private let kRTMPTimestamp_defaultTimeInterval: TimeInterval = 0
private let kRTMPTimestamp_compositiionTimeOffset = CMTime(value: 3, timescale: 30)

struct RTMPTimestamp<T: RTMPTimeConvertible> {
enum Error: Swift.Error {
case invalidSequence
}

private var startedAt = kRTMPTimestamp_defaultTimeInterval
private var updatedAt = kRTMPTimestamp_defaultTimeInterval
private var timedeltaFraction: TimeInterval = kRTMPTimestamp_defaultTimeInterval

mutating func update(_ value: T) -> UInt32 {
mutating func update(_ value: T) throws -> UInt32 {
guard updatedAt < value.seconds else {
throw Error.invalidSequence
}
if startedAt == 0 {
startedAt = value.seconds
updatedAt = value.seconds
return 0
} else {
var timedelta = (value.seconds - updatedAt) * 1000
timedeltaFraction += timedelta.truncatingRemainder(dividingBy: 1)
if 1 <= timedeltaFraction {
timedeltaFraction -= 1
timedelta += 1
}
updatedAt = value.seconds
return UInt32(timedelta)
}
var timedelta = (value.seconds - updatedAt) * 1000
timedeltaFraction += timedelta.truncatingRemainder(dividingBy: 1)
if 1 <= timedeltaFraction {
timedeltaFraction -= 1
timedelta += 1
}
updatedAt = value.seconds
return UInt32(timedelta)
}

mutating func update(_ message: RTMPMessage, chunkType: RTMPChunkType) {
Expand Down

0 comments on commit f1074c6

Please sign in to comment.