13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] ffmpeg

  • [AI 음성] 음성 합성 TTS, ChatGPT 기반 자연스러운 목소리 만들기

    [AI 음성] 음성 합성 TTS, ChatGPT 기반 자연스러운 목소리 만들기

    [AI 음성] 음성 합성 TTS, ChatGPT 기반 자연스러운 목소리 만들기

    음성 합성 TTS를 업무나 사이드 프로젝트에 붙이려는 분들이 요즘 정말 많습니다. 특히 ChatGPT로 문장을 다듬고, 그 결과를 AI 음성으로 읽게 만들면 생각보다 훨씬 자연스러운 결과가 나오거든요. 저도 처음엔 “그냥 텍스트 넣고 읽히면 끝 아닌가?” 싶었는데, 실제로 써보니까 핵심은 TTS 엔진보다도 입력 문장 설계, 쉼표와 호흡 처리, 후처리 파이프라인에 있더라고요. 이번 글에서는 제가 홈랩에서 테스트했던 방식 기준으로, ChatGPT를 문안 생성과 발화 스타일 설계에 활용하고, 검증된 음성 합성 TTS 엔진을 조합하는 실전 사례를 정리해보겠습니다.

    특히 안내 방송, 짧은 교육 콘텐츠, 내부 데모 음성처럼 “사람이 직접 녹음하기엔 번거롭고, 그렇다고 너무 기계음이면 안 되는” 상황에서 꽤 유용했습니다. 혹시 이런 경험 있으신가요? 급하게 음성이 필요해서 붙였는데, 억양이 어색하거나 숫자 읽기가 이상해서 다시 손보게 되는 경우요. 저도 그 삽질 좀 했습니다 ㅎㅎ

    음성 합성 TTS와 ChatGPT 연동 아키텍처를 보여주는 홈랩 개요 이미지

    ChatGPT로 대본을 정리하고 TTS 엔진으로 음성을 생성한 뒤 결과를 검수하는 전체 흐름 예시입니다.

    1. 왜 ChatGPT 기반 음성 합성 TTS가 중요한가

    쉽게 말해, 요즘의 TTS(Text-to-Speech, 텍스트 음성 변환)는 단순히 글자를 읽는 기술이 아니라 문장을 어떻게 써주느냐에 따라 품질이 크게 달라지는 시스템입니다. 예전에는 음성 엔진 자체 성능만 봤다면, 지금은 ChatGPT 같은 LLM(Large Language Model, 대규모 언어 모델)을 앞단에 두고 문장을 다듬는 방식이 실무에서 꽤 효과적입니다.

    • 긴 문장을 짧게 분절해서 호흡을 자연스럽게 만들 수 있습니다.
    • 숫자, 약어, 시간 표현을 사람이 듣기 좋게 바꿀 수 있습니다.
    • 상황별 톤을 맞출 수 있습니다. 예를 들어 안내 방송, 튜토리얼, 브리핑 음성은 문체가 달라야 하거든요.
    • 반복 수정 비용이 줄어듭니다. 녹음 재작업보다 훨씬 빠릅니다.

    제가 직접 해보니, 같은 TTS 엔진을 써도 원문을 그대로 넣은 버전과 ChatGPT로 다듬은 버전의 체감 차이가 꽤 컸습니다. 특히 한국어는 문장 끝맺음과 쉼표 위치가 결과에 미치는 영향이 생각보다 큽니다.

    2. 핵심 개념: ChatGPT는 음성 합성 TTS의 품질을 좌우하는 전처리 계층

    여기서 많이 헷갈리시는 포인트가 하나 있습니다. ChatGPT와 TTS는 역할이 다릅니다. ChatGPT는 문장을 생성하거나 다듬는 데 강하고, TTS 엔진은 실제 음성 파형을 만들어냅니다. 물론 서비스에 따라 음성 기능이 통합되어 보일 수는 있지만, 설계 관점에서는 역할을 분리해서 이해하는 게 좋습니다.

    구성 요소 역할 실무 포인트
    ChatGPT 대본 작성, 문장 단순화, 발화 톤 정리 호흡 단위로 문장을 쪼개는 데 유리
    TTS 엔진 텍스트를 실제 음성으로 변환 목소리 특성, 발음, 속도, 안정성이 중요
    후처리 볼륨 정리, 무음 제거, 파일 포맷 통일 배포 품질을 좌우하는 마지막 단계

    저는 이 구조를 “텍스트 품질과 음성 품질을 분리해서 튜닝한다”라고 이해하고 있습니다. 처음엔 이게 뭔가 싶었는데, 막상 분리해보면 문제 위치가 훨씬 빨리 보입니다. 문장이 문제인지, 엔진 발음이 문제인지, 파일 후처리가 문제인지 구분되거든요.

    자연스러운 AI 음성을 좌우하는 4가지

    1. 문장 길이: 한 문장에 정보가 너무 많으면 억양이 무너집니다.
    2. 쉼표와 줄바꿈: TTS가 숨 쉴 타이밍을 만들어줍니다.
    3. 숫자와 영문 표기: 10GbE, API, GPU 같은 단어는 그대로 넣으면 어색할 수 있습니다.
    4. 도메인 용어 사전: Kubernetes, ingress, homelab 같은 단어는 별도 치환 규칙이 있으면 좋습니다.

    3. 실전 사례: 홈랩 안내 음성을 만드는 TTS 파이프라인

    이번 사례는 제가 자주 쓰는 방식으로 재구성한 예시입니다. 상황은 이렇습니다. 홈랩에서 서비스 점검 안내를 짧은 음성으로 만들어야 하는데, 매번 마이크 켜고 녹음하기엔 번거롭고, 문구는 자주 바뀝니다. 그래서 아래 흐름으로 갔습니다.

    1. 원본 공지 문장을 작성합니다.
    2. ChatGPT에 넣어서 짧고 듣기 쉬운 발화형 문장으로 바꿉니다.
    3. 치환 규칙으로 숫자, 영문 약어, 특수기호를 정리합니다.
    4. 검증된 TTS 엔진으로 음성 파일을 생성합니다.
    5. ffmpeg로 볼륨과 무음 구간을 다듬습니다.
    6. 최종 WAV 또는 MP3로 배포합니다.

    중요한 건, 이 흐름이 특정 벤더 종속적이지 않다는 점입니다. ChatGPT는 앞단 품질 보정 계층이고, 음성 합성 TTS 엔진은 요구사항에 맞춰 교체 가능합니다. 상용 엔진이든 오픈소스든 구조는 비슷합니다.

    4. 구현 준비: 디렉터리 구조와 기본 환경

    예시는 Python(파이썬)으로 설명하겠습니다. 후처리는 ffmpeg를 사용합니다. ffmpeg는 오디오 변환과 볼륨 정리에 워낙 널리 쓰이는 도구라서, 인프라 쪽에서도 익숙한 분들이 많을 겁니다.

    mkdir -p tts-case-study/{input,output,scripts}
    cd tts-case-study
    python3 -m venv .venv
    source .venv/bin/activate
    pip install gTTS pydub
    

    여기서는 예제 실행 난이도를 낮추기 위해 gTTS를 사용하겠습니다. gTTS는 Google Text-to-Speech 기반의 파이썬 라이브러리로 널리 알려져 있고, 빠르게 프로토타입을 만들 때 편합니다. 다만 실서비스에서는 목소리 선택폭, 발화 제어, 라이선스, 네트워크 의존성 등을 따져서 다른 음성 합성 엔진을 검토하시는 게 좋습니다.

    입력 텍스트 파일도 하나 만들어보겠습니다.

    cat > input/source.txt <<'EOF'
    오늘 밤 11시부터 홈랩 스토리지 점검이 진행됩니다.
    예상 시간은 약 30분이며, 일부 서비스 접속이 지연될 수 있습니다.
    점검이 끝나면 다시 안내드리겠습니다.
    EOF
    
    ChatGPT 전처리 후 음성 합성 TTS로 전달되는 흐름을 설명하는 이미지

    원본 공지 문장을 발화용 문장으로 다듬고, 이후 TTS와 후처리 단계로 넘기는 흐름을 표현한 구성도입니다.

    5. ChatGPT로 발화용 스크립트 다듬기

    여기서 중요한 포인트! 문장을 잘 쓰는 게 절반입니다. 제가 실제로 써보니까, TTS 품질이 아쉬울 때 엔진을 바꾸기 전에 먼저 문장을 손보는 게 더 빠른 경우가 많았습니다.

    예를 들어 원문이 아래처럼 딱딱하면 음성이 확 죽습니다.

    오늘 밤 11시부터 홈랩 스토리지 점검이 진행됩니다. 예상 시간은 약 30분이며, 일부 서비스 접속이 지연될 수 있습니다.

    이걸 발화형으로 바꾸면 이렇게 됩니다.

    안내드립니다. 오늘 밤 11시부터 홈랩 스토리지 점검이 진행됩니다. 예상 시간은 약 30분입니다. 점검 중에는 일부 서비스 접속이 잠시 지연될 수 있습니다.

    차이가 좀 느껴지시죠? 의미는 거의 같은데 듣기 편해집니다. ChatGPT에 요청할 때는 아래처럼 제약 조건을 명확히 주는 프롬프트가 좋습니다.

    다음 문장을 한국어 TTS용 발화 스크립트로 다듬어 주세요.
    조건:
    - 한 문장은 20자~40자 정도로 유지
    - 숫자는 사람이 듣기 쉽게 풀어쓰기
    - 문장은 짧게 끊고 쉼표를 최소화
    - 딱딱한 공지문보다 자연스러운 안내 톤 사용
    - 의미는 바꾸지 말 것
    

    실무에서는 이 프롬프트를 고정 템플릿으로 두는 걸 추천드립니다. 저도 처음엔 요청할 때마다 다르게 썼는데, 결과 편차가 커서 나중엔 템플릿을 따로 뽑아놨습니다.

    6. Python으로 음성 합성 TTS 자동화하기

    이제 발화용 텍스트를 음성 파일로 변환해보겠습니다. 아래 예제는 텍스트 정리, 문장 단위 분리, TTS 생성, 파일 저장까지 한 번에 처리합니다.

    from pathlib import Path
    from gtts import gTTS
    import re
    
    BASE_DIR = Path(__file__).resolve().parent.parent
    INPUT_FILE = BASE_DIR / "input" / "source.txt"
    OUTPUT_FILE = BASE_DIR / "output" / "announcement.mp3"
    
    
    def normalize_text(text: str) -> str:
        replacements = {
            "11시": "열한 시",
            "30분": "삼십 분",
            "홈랩": "홈랩",
            "API": "에이피아이",
            "GPU": "지피유",
        }
        for src, dst in replacements.items():
            text = text.replace(src, dst)
    
        text = re.sub(r"\s+", " ", text).strip()
        return text
    
    
    def to_speech(text: str, output_path: Path) -> None:
        tts = gTTS(text=text, lang="ko")
        tts.save(str(output_path))
    
    
    def main() -> None:
        raw = INPUT_FILE.read_text(encoding="utf-8")
        normalized = normalize_text(raw)
        to_speech(normalized, OUTPUT_FILE)
        print(f"saved: {OUTPUT_FILE}")
    
    
    if __name__ == "__main__":
        main()
    

    실행은 간단합니다.

    python scripts/make_tts.py
    

    조금 더 손보려면 문장 단위로 파일을 나눈 뒤 이어 붙이는 방법도 있습니다. 이 방식은 특정 문장만 재생성할 수 있어서 운영에 꽤 편합니다. 변경이 잦은 공지 시스템이라면 특히 그렇습니다.

    ffmpeg -i output/announcement.mp3 -af "volume=1.5" output/announcement-loud.mp3
    

    볼륨 보정은 생각보다 중요합니다. 생성된 음성이 너무 작으면, 엔진 품질이 나쁜 것처럼 느껴질 때가 있거든요. 실제로는 단순 레벨 문제인 경우도 많습니다.

    Python으로 AI 음성과 음성 합성 TTS를 자동화하는 구현 예시 이미지

    스크립트 실행, 생성된 음성 파일, ffmpeg 후처리 단계가 이어지는 구현 흐름 예시입니다.

    7. ⚠️ 제가 실제로 부딪힌 문제와 해결 방법

    이 섹션이 제일 중요할 수도 있겠습니다. 음성 합성 TTS 프로젝트는 데모는 빨리 나오는데, 막상 배포하려고 하면 자잘한 문제가 계속 튀어나옵니다.

    1) 숫자와 단위가 이상하게 읽히는 문제

    예를 들어 10GbE, 3TB, 23:00 같은 표기는 그대로 넣으면 기대와 다르게 읽힐 수 있습니다. 저도 처음엔 엔진 문제인 줄 알았는데, 실제로는 입력 표기 문제가 더 컸습니다.

    • 23:00 → 밤 열한 시
    • 30min → 삼십 분
    • 10GbE → 텐 지가비트 이더넷 또는 서비스 문맥에 맞는 한글 표기

    정규화(normalization, 입력 표준화) 사전을 미리 두면 훨씬 안정적입니다.

    2) 문장이 길면 억양이 무너지는 문제

    이건 거의 매번 겪었습니다. 한 문장에 조건절이 두세 개 붙으면 AI 음성이 어디서 끊어야 할지 애매해하더라고요. 해결은 단순합니다. 짧게 쪼개면 됩니다. 정말 기본인데 효과가 큽니다.

    3) 한국어와 영어가 섞일 때 부자연스러운 문제

    예를 들어 “스토리지 API 상태를 확인하세요” 같은 문장은 엔진에 따라 API를 영어식으로 읽거나, 너무 또박또박 끊어 읽기도 합니다. 이런 경우는 아래 중 하나로 정리하는 게 좋았습니다.

    • API → 에이피아이
    • UI → 유아이
    • NAS → 나스

    물론 팀 내부 용어가 있으면 거기에 맞춰 통일해야 합니다. 여기서 중요한 건 정답 하나를 찾는 게 아니라, 프로젝트 안에서 읽기 규칙을 고정하는 겁니다.

    4) 음성 파일 길이가 들쭉날쭉한 문제

    같은 톤으로 만들어도 문장 길이에 따라 파일 길이가 크게 달라집니다. 안내 방송처럼 재생 타이밍이 중요한 경우엔, 문장 길이를 통제하고 중간 무음을 후처리로 정리해야 합니다.

    ffmpeg -i output/announcement.mp3 -af "silenceremove=1:0:-40dB" output/announcement-trimmed.mp3
    

    저는 무음을 너무 공격적으로 자르다가 문장 사이 호흡까지 날려먹은 적도 있었습니다. 드디어 됐다 싶었는데, 다시 들어보니 너무 숨 가쁘더라고요. 그래서 최종값은 꼭 귀로 다시 확인합니다.

    8. 결과 검증: 무엇을 기준으로 좋다고 볼 것인가

    음성 결과는 주관적이기 쉽습니다. 그래서 저는 아래처럼 체크리스트로 봅니다.

    1. 첫 청취 이해도: 한 번 들었을 때 내용이 바로 들어오는가
    2. 숫자/시간 오독 여부: 서비스 공지에서 특히 중요
    3. 문장 끝 억양: 질문처럼 들리거나 끊기는 느낌이 없는가
    4. 볼륨 일관성: 다른 음원과 함께 써도 튀지 않는가
    5. 재생 환경 적합성: 모바일 스피커, 이어폰, PC 스피커에서 모두 무난한가

    가능하면 2~3명이 들어보는 게 좋습니다. 제가 익숙해진 문장은 문제를 놓치기 쉽거든요. 특히 음성 합성과 목소리 생성 쪽은 만든 사람 귀보다 처음 듣는 사람 반응이 더 정확한 경우가 많았습니다.

    검증 항목 좋은 상태 다시 손봐야 할 상태
    문장 길이 짧고 끊김이 자연스러움 호흡이 길고 끝이 뭉개짐
    숫자 읽기 시간/단위가 직관적 영문 약어처럼 들리거나 오독됨
    톤 안내 목적에 맞음 과하게 딱딱하거나 지나치게 경쾌함
    후처리 볼륨이 일정함 작거나 무음 구간이 어색함
    음성 합성 TTS 결과와 AI 음성 품질을 검수하는 대시보드 이미지

    오디오 파형, 재생 길이, 청취 체크리스트를 함께 보며 결과를 검수하는 장면입니다.

    9. 정리와 다음 단계: ChatGPT, 목소리 생성, AI 음성을 제대로 연결하는 법

    이번 사례에서 핵심은 명확합니다. 자연스러운 목소리는 TTS 엔진 하나로 해결되지 않습니다. ChatGPT로 문장을 발화 친화적으로 정리하고, 음성 합성 TTS 엔진에 맞는 입력 규칙을 만들고, 마지막에 후처리로 다듬어야 결과가 안정적입니다. 저도 처음엔 엔진만 바꾸면 끝날 줄 알았는데, 실제로 써보니까 가장 큰 차이는 텍스트 전처리에서 나더라고요.

    정리하면 이렇게 보시면 됩니다.

    • ChatGPT: 문장 다듬기, 톤 정리, 발화 분절
    • TTS: 실제 음성 생성
    • 후처리: 볼륨, 무음, 파일 포맷 정리

    이 흐름만 잡아도 품질이 한 단계 올라갑니다. 음성 합성 TTS를 처음 붙이시는 분이라면, 무조건 거대한 시스템부터 만들지 마시고 짧은 공지문 3개 정도로 먼저 반복 테스트해보세요. 그게 제일 빠릅니다.

    다음 글에서는 SSML(Speech Synthesis Markup Language, 음성 합성 마크업 언어)을 지원하는 엔진에서 쉼표, 강조, 휴지(pause) 제어를 어떻게 다르게 가져갈지 다뤄볼 예정입니다. 이전 글에서 다뤘던 홈랩 자동화 파이프라인과 연결해서 보면 더 이해가 쉬우실 겁니다.

    자주 묻는 질문

    • Q. ChatGPT만으로 바로 TTS를 끝낼 수 있나요?
      A. 서비스 구성에 따라 통합된 경험은 가능하지만, 설계상으로는 문장 생성과 음성 생성을 분리해서 보는 편이 운영에 유리했습니다.
    • Q. 오픈소스 엔진이 꼭 불리한가요?
      A. 그렇진 않습니다. 다만 목소리 선택폭, 한국어 발음, 운영 복잡도, 하드웨어 요구사항을 같이 봐야 합니다.
    • Q. 가장 먼저 튜닝할 부분은 뭔가요?
      A. 엔진 교체보다 먼저 입력 문장 길이와 숫자 표기를 정리해보세요. 체감 차이가 큽니다.
    ChatGPT 기반 음성 합성 TTS 파이프라인을 요약한 인포그래픽

    문장 전처리부터 음성 생성과 후처리까지, 실전 파이프라인의 핵심 포인트를 한눈에 정리한 요약 이미지입니다.

  • [홈랩] Frigate NVR 녹화 끊김·성능 저하 해결 디버깅 팁

    [홈랩] Frigate NVR 녹화 끊김·성능 저하 해결 디버깅 팁

    [홈랩] Frigate NVR 녹화 끊김·성능 저하 해결 디버깅 팁

    홈랩에서 카메라 몇 대만 붙여도 처음엔 잘 돌아가다가, 어느 순간 녹화가 뚝뚝 끊기고 CPU가 치솟는 경험 한 번쯤 있으실 겁니다. 저도 Frigate NVR 녹화 끊김 문제 때문에 꽤 오래 삽질했었는데요. 처음엔 카메라 문제인가 싶었고, 그다음엔 디스크가 느린가 싶었고, 나중엔 네트워크까지 의심하게 되더라고요. 근데 실제로 써보니까 이런 증상은 한 군데만 보는 식으로는 잘 안 잡힙니다. 입력 스트림, 디코딩, 감지 파이프라인, 저장소, 컨테이너 자원을 같이 봐야 하거든요.

    이번 글에서는 제가 홈랩에서 자주 만났던 Frigate NVR 성능 문제를 기준으로, 어디부터 확인해야 하는지 순서대로 정리해보겠습니다. 막연하게 “서버가 느린가?” 수준에서 끝내지 않고, 실제 로그와 명령어로 좁혀가는 방식입니다. 지금도 녹화 파일이 띄엄띄엄 생기거나, 타임라인이 비거나, 감지가 몰릴 때 프레임이 급격히 떨어지는 상황이라면 꽤 바로 도움이 되실 겁니다.

    Frigate NVR 녹화 끊김 점검을 위한 홈랩 아키텍처 개요

    Frigate NVR, IP 카메라, 스토리지, GPU 또는 iGPU 가속 경로를 한눈에 보여주는 홈랩 구성 예시입니다.

    Frigate NVR 녹화 끊김이 생기는 구조부터 이해해봅시다

    쉽게 말해 Frigate는 카메라에서 들어오는 영상 스트림을 받아서, 필요한 경우 decode(디코드, 압축 해제)하고, detect(객체 감지)에 쓰고, record(녹화)용으로 저장합니다. 여기서 중요한 포인트가 있습니다. 우리가 보기엔 그냥 “영상 하나”지만, 내부적으로는 역할이 나뉘어 있는 경우가 많습니다.

    • record(녹화): 원본에 가깝게 저장하는 흐름입니다.
    • detect(감지): 객체 인식용으로 해상도나 프레임을 낮춰 쓰는 경우가 많습니다.
    • ffmpeg: 스트림을 받아서 변환하고 전달하는 핵심 도구입니다.
    • hwaccel(하드웨어 가속): CPU 대신 GPU나 iGPU를 활용해 디코딩 부담을 줄입니다.

    이 구조를 모르고 접근하면 보통 녹화 끊김이 생겼을 때 CPU만 봅니다. 저도 처음엔 그랬거든요. 근데 실제 원인은 CPU가 아니라 RTSP 스트림 불안정, 디스크 I/O 병목, 컨테이너 볼륨 권한 문제, detect와 record를 같은 고해상도 스트림으로 태운 설정 같은 쪽에서 더 자주 나왔습니다.

    Frigate 디버깅 순서: 제가 먼저 확인하는 체크리스트

    Frigate 디버깅은 순서가 중요합니다. 여기서 한 번에 다 건드리면 더 헷갈립니다. 저는 아래 순서로 봅니다.

    1. 컨테이너와 Frigate 로그에 에러가 있는지 확인합니다.
    2. CPU, 메모리, 디스크 I/O 사용량을 동시에 봅니다.
    3. 카메라 RTSP 스트림이 독립적으로 안정적인지 테스트합니다.
    4. detect용 스트림과 record용 스트림을 분리했는지 확인합니다.
    5. 하드웨어 가속이 실제로 적용됐는지 확인합니다.
    6. 저장소가 로컬 디스크인지, 느린 네트워크 스토리지인지 확인합니다.

    여기서 중요한 건 증상과 원인을 분리하는 겁니다. 예를 들어 CPU 90%는 원인이 아니라 결과일 수 있습니다. RTSP 재연결이 반복되면 ffmpeg 프로세스가 늘어나고, 그게 다시 전체 성능 저하로 보일 수 있거든요.

    실전 구현 1: 로그와 자원부터 확인합니다

    가장 먼저 아래 명령어부터 보시면 됩니다. Docker(도커) 환경 기준으로 적어볼게요.

    docker ps
    
    docker logs --tail=200 frigate
    
    docker stats frigate
    
    df -h
    
    iostat -xz 1
    
    free -m
    
    top

    제가 직접 해보니 여기서 이미 방향이 잡히는 경우가 많았습니다. 예를 들어 docker stats에서 CPU가 높게 치솟는데 디스크는 한가하다면 디코딩이나 감지 쪽을 먼저 의심하게 되고요. 반대로 CPU는 괜찮은데 iostat에서 await가 길게 나오면 저장소 병목일 가능성이 큽니다.

    로그에서 특히 자주 보는 단서는 이런 것들입니다.

    • Connection timed out: 카메라 또는 네트워크 구간 문제일 수 있습니다.
    • No frames received: 스트림이 끊기거나 인증이 꼬였을 수 있습니다.
    • error while decoding: 코덱, 하드웨어 가속, 손상된 스트림을 의심합니다.
    • Unable to write: 저장소 권한 또는 디스크 공간 문제일 수 있습니다.

    자원 병목을 빠르게 비교하는 기준

    증상 먼저 볼 곳 의심 원인 우선 조치
    녹화가 띄엄띄엄 저장됨 디스크 I/O, 볼륨 경로 저장소 병목, 권한 문제 로컬 SSD 확인, 마운트 경로 재검토
    CPU가 계속 높음 ffmpeg 프로세스, hwaccel 소프트웨어 디코딩, 고해상도 detect 하드웨어 가속 적용, detect 스트림 분리
    특정 카메라만 자주 끊김 카메라 RTSP 테스트 카메라 펌웨어, 네트워크 불안정 개별 스트림 재생 테스트
    감지 몰릴 때 전체가 느려짐 객체 감지 설정, 해상도 detect 과부하 해상도/프레임 조정

    실전 구현 2: 카메라 스트림과 설정을 분리해서 봅니다

    Frigate NVR 성능 문제를 줄이는 데서 가장 체감이 큰 건, 보통 녹화용 스트림과 감지용 스트림을 분리하는 겁니다. 처음엔 “어차피 같은 카메라 영상인데 왜 나누지?” 싶었는데, 이게 효과가 꽤 큽니다. 감지는 낮은 해상도와 적당한 프레임으로도 충분한 경우가 많거든요.

    cameras:
      front_door:
        ffmpeg:
          inputs:
            - path: rtsp://USER:[email protected]:554/stream1
              roles:
                - record
            - path: rtsp://USER:[email protected]:554/stream2
              roles:
                - detect
        detect:
          width: 1280
          height: 720
          fps: 5
        record:
          enabled: true

    위 예시는 원리를 보여주기 위한 단순한 형태입니다. 핵심은 이겁니다.

    1. record는 화질 보존이 우선입니다.
    2. detect는 낮은 부담으로 안정성이 우선입니다.
    3. 모든 역할을 같은 고해상도 스트림 하나로 몰아주면 CPU가 쉽게 올라갑니다.
    Frigate NVR 성능 문제를 줄이기 위한 record와 detect 스트림 분리 구성

    녹화용 원본 스트림과 감지용 저해상도 스트림을 나눠 CPU 부담을 줄이는 구성 예시입니다.

    그리고 RTSP 스트림 자체가 안정적인지도 꼭 따로 확인해보셔야 합니다. 저는 이걸 나중에 봤다가 시간을 많이 썼습니다 ㅎㅎ

    ffprobe rtsp://USER:[email protected]:554/stream1
    
    ffplay rtsp://USER:[email protected]:554/stream1

    Frigate 밖에서 재생이 불안정하면, Frigate 안에서 아무리 튜닝해도 해결이 안 됩니다. 여기서 끊기면 카메라 자체 설정, 스위치 포트, PoE 상태, 무선 구간 사용 여부까지 봐야 합니다.

    실전 구현 3: 하드웨어 가속과 저장소를 점검합니다

    저도 처음엔 “서버 CPU가 꽤 괜찮은데 왜 이러지?” 했었는데, 실제로 써보니까 하드웨어 가속이 빠졌거나 제대로 붙지 않은 상태가 정말 흔합니다. 특히 여러 대 카메라를 붙이면 소프트웨어 디코딩만으로는 금방 버거워집니다.

    리눅스에서 장치가 보이는지부터 확인합니다.

    ls /dev/dri
    
    vainfo
    
    docker exec -it frigate ls /dev/dri

    여기서 장치가 보이지 않으면 컨테이너에 디바이스 전달이 안 된 경우가 많습니다. 반대로 장치는 보이는데 여전히 CPU가 높다면, ffmpeg 쪽 옵션이나 실제 사용 코덱과 가속 경로가 맞지 않는 경우가 있습니다. 이런 부분은 하드웨어마다 조금씩 다르기 때문에, 무리해서 확정적으로 단정하기보다 로그와 실제 CPU 변화를 같이 보시는 게 안전합니다.

    저장소도 중요합니다. 특히 NVR 오류 해결을 하다 보면 네트워크 스토리지에 바로 녹화하는 구성이 종종 보이는데요. 편하긴 한데, 지연(latency, 지연 시간)이 조금만 늘어나도 타임라인이 비거나 녹화가 밀리는 증상이 생길 수 있습니다. 저는 가능하면 로컬 SSD에 먼저 기록하고, 이후 보관 정책으로 넘기는 방식을 선호합니다.

    ⚠️ 실제로 자주 만난 Frigate 녹화 끊김 문제와 해결법

    여기부터는 제가 직접 해보니 재현 빈도가 높았던 케이스들입니다. Frigate 디버깅할 때 꽤 자주 만납니다.

    1. 특정 시간대에만 녹화 끊김이 생기는 경우

    이건 네트워크 트래픽 몰림이나 디스크 백그라운드 작업이 원인인 경우가 많았습니다. 백업, 썸네일 작업, 다른 컨테이너 업데이트가 겹치면 체감상 “Frigate만 문제”처럼 보이거든요.

    • 해결 팁: 같은 시간대에 돌아가는 작업 스케줄을 확인합니다.
    • 확인 명령어: <code>docker stats, iostat -xz 1, dmesg

    2. 녹화는 되는데 감지 순간만 프레임이 떨어지는 경우

    detect 해상도나 fps가 과한 경우가 많았습니다. 특히 카메라 수가 늘어날수록 누적 부담이 커집니다.

    • 해결 팁: detect 해상도와 fps를 낮춰봅니다.
    • 확인 포인트: 객체 감지 정확도와 CPU 사용량을 같이 봅니다.

    3. 컨테이너 재시작 후부터 녹화 경로 오류가 나는 경우

    볼륨 마운트 경로가 달라졌거나 권한이 꼬인 경우가 있었습니다. 로그에는 단순한 write error처럼 보이는데, 알고 보면 호스트 경로 소유권 문제더라고요.

    ls -al /path/to/frigate/media
    
    id
    
    docker inspect frigate
    • 해결 팁: 컨테이너 사용자와 호스트 디렉터리 권한을 같이 확인합니다.

    4. 카메라 한 대만 유독 불안정한 경우

    이건 Frigate가 아니라 카메라 쪽 문제였던 적이 많았습니다. 펌웨어, RTSP 세션 제한, 비트레이트 과다, 스위치 포트 상태 같은 게 숨어 있더라고요.

    • 해결 팁: 카메라를 직접 재생해보고, 동일 모델 다른 장비와 비교합니다.
    • 추가 확인: 고정 비트레이트(CBR)와 키프레임 간격도 확인해보면 좋습니다.

    CPU 사용량, 디스크 지연, 로그 메시지를 함께 보면서 병목 지점을 찾아가는 실제 디버깅 흐름 예시입니다.

    검증: Frigate 성능 개선 후 무엇을 보면 될까요?

    설정을 바꿨으면 바로 체감으로만 판단하지 마시고, 최소 몇 시간은 지표를 보시는 걸 권장드립니다. 저도 처음엔 “드디어 됐다!” 싶었는데, 밤에 다시 끊겨서 허탈했던 적이 있거든요.

    1. Frigate 타임라인에 빈 구간이 줄었는지 확인합니다.
    2. 컨테이너 CPU 사용률이 이전보다 안정적인지 봅니다.
    3. 디스크 await와 utilization이 과하게 치솟지 않는지 봅니다.
    4. 특정 카메라의 재연결 로그가 줄었는지 확인합니다.
    5. 감지 정확도가 너무 희생되지 않았는지 같이 봅니다.

    여기서 중요한 포인트! 성능 최적화와 감지 품질은 항상 트레이드오프가 있습니다. detect 해상도와 fps를 너무 낮추면 CPU는 편해지지만, 작은 객체를 놓칠 수 있거든요. 그래서 저는 한 번에 크게 바꾸지 않고, 한 항목씩 줄여가면서 로그와 결과를 비교합니다.

    조치 항목 기대 효과 주의점
    detect fps 낮춤 CPU 감소 빠른 움직임 감지 저하 가능
    detect 해상도 낮춤 디코딩/감지 부담 감소 작은 객체 인식률 저하 가능
    하드웨어 가속 적용 CPU 대폭 완화 가능 장치 전달, 코덱 호환 확인 필요
    로컬 SSD 저장 녹화 안정성 향상 보관 공간 관리 필요
    Frigate NVR 녹화 끊김 해결 후 안정화된 타임라인과 모니터링 결과

    타임라인 빈 구간이 줄고 CPU와 디스크 지표가 안정화된 결과를 보여주는 대시보드 예시입니다.

    정리: Frigate NVR 녹화 끊김은 한 군데만 보면 잘 안 잡힙니다

    이번 글을 한 줄로 요약하면 이겁니다. Frigate NVR 녹화 끊김 문제는 카메라, ffmpeg, 감지 설정, 저장소, 하드웨어 가속을 같이 봐야 풀립니다. 저도 처음엔 이게 뭔가 싶었는데, 결국 가장 효과적이었던 건 복잡한 튜닝보다도 원인 후보를 하나씩 지워가는 디버깅 순서였습니다.

    특히 아래 네 가지는 거의 항상 점검하시는 걸 추천드립니다.

    • detect와 record 스트림을 분리했는지
    • 하드웨어 가속이 실제로 적용됐는지
    • RTSP 스트림 자체가 안정적인지
    • 녹화 저장소가 병목이 아닌지

    이 방식으로 보면 Frigate NVR 성능 문제가 생각보다 빨리 좁혀집니다. 다음 글에서는 홈랩 기준으로 저장소 분리 전략이나, 카메라 수가 늘어났을 때 운영 포인트도 따로 정리해보겠습니다. 이전에 다뤘던 컨테이너 자원 분리 방식과 같이 보시면 더 이해가 잘 되실 거예요.

    최적화 전후의 CPU 사용량, 녹화 안정성, 디버깅 포인트를 한 장으로 정리한 요약 인포그래픽입니다.

    자주 묻는 질문

    Q1. CPU만 낮추면 Frigate 디버깅이 끝난 걸까요?

    아닙니다. CPU가 낮아도 디스크 쓰기 지연이나 RTSP 재연결이 있으면 녹화는 계속 끊길 수 있습니다. 그래서 로그와 저장소 지표를 같이 봐야 합니다.

    Q2. Frigate NVR 녹화 끊김이 있을 때 가장 먼저 볼 항목은 뭔가요?

    저는 컨테이너 로그, 카메라 스트림 단독 재생, 디스크 I/O 이 세 가지부터 봅니다. 이 세 군데에서 방향이 잡히는 경우가 많았습니다.

    Q3. 무조건 detect 해상도를 낮추면 되나요?

    그건 아닙니다. 작은 객체를 중요하게 보시는 환경이면 감지 품질이 너무 떨어질 수 있습니다. 한 번에 크게 바꾸지 말고 단계적으로 조정해보시는 게 좋습니다.