본문 바로가기

xcode

xcode 아이폰 앱에서 rtsp streaming 하는 법 (ffmpeg 옵션 설정 하는 법)

 

 


 

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(가변 프레임)으로 변경하면 더 빠르게 전송됨.