import Foundation
import AVFoundation
import ffmpegkit
class RTSPStreamer {
static var player: AVPlayer?
static var playerLayer: AVPlayerLayer?
// 스트리밍 시작
static func startStreaming(url: String, completion: @escaping (Bool) -> Void) {
// 이전에 실행 중인 FFmpeg 세션이 있다면 종료
if FFmpegKit.isRunning() {
print("FFmpeg is still running, please wait before starting a new stream.")
completion(false)
return
}
guard let streamUrl = URL(string: url) else {
completion(false)
return
}
// AVPlayer 초기화
player = AVPlayer(url: streamUrl)
playerLayer = AVPlayerLayer(player: player)
// 비디오 플레이어 레이어 설정
playerLayer?.videoGravity = .resizeAspectFill
// 스트리밍 시작
player?.play()
completion(true)
}
// 스트리밍 중단
static func stopStreaming() {
// FFmpeg 세션이 실행 중이면 취소
FFmpegKit.cancel()
// AVPlayer와 playerLayer 리소스 해제
player?.pause()
playerLayer?.removeFromSuperlayer()
player = nil
playerLayer = nil
}
// RTSP 스트리밍을 위한 FFmpeg 명령어 실행
static func startFFmpegStream(rtspUrl: String) {
if let captureDevice = AVCaptureDevice.default(for: .video) {
do {
try captureDevice.lockForConfiguration()
// 초점을 0.5 (중간 거리)로 설정
if captureDevice.isFocusModeSupported(.locked) {
captureDevice.setFocusModeLocked(lensPosition: 0.5) { (time) in
print("초점 설정 완료")
}
}
captureDevice.unlockForConfiguration()
} catch {
print("초점 설정 실패: \(error)")
}
}
let ffmpegCommand = """
-f avfoundation -framerate 30 -video_size 1920x1080 -i 0 \
-pix_fmt nv12 -c:v h264_videotoolbox -b:v 5500k -maxrate 8800k -bufsize 11000k \
-preset ultrafast -tune zerolatency -vsync cfr -use_wallclock_as_timestamps 1 \
-fflags +genpts+igndts -rtbufsize 200M -fps_mode passthrough \
-f rtsp -rtsp_transport tcp \(rtspUrl)
"""
// FFmpeg 스트리밍 명령어 실행
FFmpegKit.executeAsync(ffmpegCommand) { session in
if let returnCode = session?.getReturnCode(), returnCode.getValue() == 0 {
print("Streaming started successfully")
} else {
print("Failed to start streaming")
}
}
}
}
1080p 에서 아래 옵션 넣어야지 송출이 가능
-b:v 5500k -maxrate 8800k -bufsize 11000k
720p에서 아래 옵션 없어도 송출가능하나 화질이 안좋음
-b:v 2500k -maxrate 4000k -bufsize 5000k
// 720p 적용시
let ffmpegCommand = """
-f avfoundation -framerate 30 -video_size 1280x720 -i 0 \
-pix_fmt nv12 -c:v h264_videotoolbox -b:v 2500k -maxrate 4000k -bufsize 5000k \
-preset ultrafast -tune zerolatency -fflags +genpts \
-f rtsp -rtsp_transport tcp \(rtspUrl)
"""
// 1080p 적용시
let ffmpegCommand = """
-f avfoundation -framerate 30 -video_size 1920x1080 -i 0 \
-pix_fmt nv12 -c:v h264_videotoolbox -b:v 5500k -maxrate 8800k -bufsize 11000k \
-preset ultrafast -tune zerolatency -vsync cfr -use_wallclock_as_timestamps 1 \
-fflags +genpts+igndts -rtbufsize 200M -fps_mode passthrough \
-f rtsp -rtsp_transport tcp \(rtspUrl)
"""
세로, 가로 구분 코드 rev.0 (세로모드가 딜레이가 크다)
if mode == "세로화면송출" {
ffmpegCommand = """
-f avfoundation -framerate 30 -video_size 1920x1080 -i 0 \
-pix_fmt nv12 -c:v h264_videotoolbox -b:v 5500k -maxrate 8800k -bufsize 11000k \
-g 15 \
-preset ultrafast -tune zerolatency -vsync cfr -use_wallclock_as_timestamps 1 \
-vf "transpose=1, format=yuv420p" \
-fflags +genpts+igndts -rtbufsize 200M -fps_mode passthrough \
-f rtsp -rtsp_transport tcp \(rtspUrl)
"""
} else if mode == "가로화면송출" {
ffmpegCommand = """
-f avfoundation -framerate 30 -video_size 1920x1080 -i 0 \
-pix_fmt nv12 -c:v h264_videotoolbox -b:v 5500k -maxrate 8800k -bufsize 11000k \
-preset ultrafast -tune zerolatency -vsync cfr -use_wallclock_as_timestamps 1 \
-fflags +genpts+igndts -rtbufsize 200M -fps_mode passthrough \
-f rtsp -rtsp_transport tcp \(rtspUrl)
"""
}
세로, 가로 구분 코드 rev.1 (세로모드 딜레이가 많이 줄음)
if mode == "세로화면송출" {
ffmpegCommand = """
-f avfoundation -framerate 30 -video_size 1280x720 -i 0 \
-pix_fmt nv12 -c:v h264_videotoolbox -b:v 4000k -maxrate 6000k -bufsize 8000k \
-g 15 -preset ultrafast -tune zerolatency -profile:v baseline -level:v 3.1 \
-vsync vfr -use_wallclock_as_timestamps 1 \
-vf "transpose=1, format=yuv420p" \
-fflags nobuffer+genpts+igndts -rtbufsize 100M -fps_mode passthrough \
-f rtsp -rtsp_transport tcp \(rtspUrl)
"""
} else if mode == "가로화면송출" {
ffmpegCommand = """
-f avfoundation -framerate 30 -video_size 1920x1080 -i 0 \
-pix_fmt nv12 -c:v h264_videotoolbox -b:v 5500k -maxrate 8800k -bufsize 11000k \
-preset ultrafast -tune zerolatency -vsync cfr -use_wallclock_as_timestamps 1 \
-fflags +genpts+igndts -rtbufsize 200M -fps_mode passthrough \
-f rtsp -rtsp_transport tcp \(rtspUrl)
"""
}
변경 사항 & 설명
1️⃣ 비트레이트 조정 (화질과 딜레이 균형)
- -b:v 5500k → 4000k, -maxrate 8800k → 6000k, -bufsize 11000k → 8000k
- 이유: 네트워크 대역폭을 줄이면 패킷 전송 속도가 빨라져서 딜레이가 줄어듦.
2️⃣ 키 프레임 간격 (-g) 줄이기
- -g 15
- 이유: 키 프레임 간격을 줄이면 프레임이 빨리 업데이트됨.
3️⃣ 인코딩 프로필 낮추기
- -profile:v baseline -level:v 3.1
- 이유: 고사양 인코딩 옵션을 줄여서 지연 시간 감소.
4️⃣ -fflags 버퍼링 제거
- -fflags nobuffer+genpts+igndts
- 이유: FFmpeg의 내부 버퍼링을 줄여서 즉시 전송.
5️⃣ -rtbufsize 값 줄이기
- -rtbufsize 200M → 100M
- 이유: RTSP 버퍼 크기를 줄여서 실시간성 향상.
6️⃣ -vsync vfr (Variable Frame Rate)
- -vsync cfr → -vsync vfr
- 이유: CFR(고정 프레임)은 일정한 프레임 유지 때문에 딜레이 발생 가능.
→ VFR(가변 프레임)으로 변경하면 더 빠르게 전송됨.
'xcode' 카테고리의 다른 글
애플 개발자 프로그램 종류 (무료 자격시 빌드된 앱 유효기간은 7일) (0) | 2025.03.06 |
---|---|
xcode에서 Sandbox 문제 발생시 해결법 (0) | 2025.03.04 |