꽃삽질 : ffmpeg 를 이용한 rtsp stream 녹화

2021년 5월 현재, 다음 글에 좀 더 제대로된 정보를 정리했다.
이 글은 그냥 과거 기록으로 남겨놓기로.

꽃삽질 : RTSP 스트림 녹화 (최종판?)


** 이 계획(?)의 최신 소식은 이 글 아래 쪽에.


꽃삽질 자취 기록:

며칠 이걸로 고생했는데, 답을 찾아내진 못했다. 이건, 녹화를 시행하는 쪽 기기 문제도 있겠지만, 영상을 날려주는 rtsp 서버 쪽에 더 큰 문제가 있는 듯 하다.

Xiaomi Dafang 을 활용(?)하여 rtsp 서버를 만들었다. tinyCam 등을 활용하면, 적어도 ‘보는 데’는 지장이 없다. 다만, 이걸 녹화하여 보존하려하니 무리가 따른다.

Dafang Custom Firmware 에 녹화 기능이 있긴 하다. 그런데 이 기능을 사용하면 microSD 를 이용해야만 하고, 수명 문제도 있고, 영상을 확인할 때 좀 애매한 면이 있다.

따라서, 다른 기기에서 이 영상을 실시간으로 받아 저장하는 방식을 택했는데..
구글의 뒤져 구한 코드들을 짜깁기 해서 다음과 같은 ffmpeg 명령을 만들었다.

ffmpeg -stimeout 1000000 \
 -abort_on empty_output \
 -rtsp_transport tcp \
 -fflags nobuffer \
 -an \
 -i rtsp://ip:port/unicast \
 -map 0:v \
 -c copy \
 -metadata title="" \
 -f segment \
 -segment_time 600 \
 -segment_wrap 100 \
 -reset_timestamps 1 \
 -strftime 1 \
 "file-%Y%m%d-%H%M.mp4"

그런데.. 이거 어떨 땐 40분쯤 잘 버티기도 하지만, 대부분은 수분 이내에 죽어버린다. 이유는 명확하질 않다. 정확한 오류가 나타날 때도 있지만(서버 연결 불가 등), 그냥 멈추는 경우가 대부분이다.

이걸 해결하기 위해 구글을 뛰어다니고(?), Dafang C.F 에도 문의를 해봤는데, 아직 명쾌한 해답은 찾질 못했다. 막연한 내 짐작으로는, 서버, 즉 Dafang 의 하드웨어 자체가 단단하질 못해서, 즉, 영상을 오류없이 잘 제공해줄만큼 견고한 상태가 아니기에 이런 문제가 발생하는 듯 하다. Wifi 시그널 문제도 있을테고, 서버 자체도 조금 불안한 면이 있을테고.

따라서, 그야말로 24/7 영상을 저장하기란 문제가 있어 보인다.

하여.. 고민하다가, 그냥 ffmpeg 를 무한루프로 돌리기로 했다.

** 2021.04.30
아래 보다는, 좀 더 간단히한 새로운 방식이 더 나아보인다. 아래 ‘새 명령’ 항목에 추가했다.

while :
do
	# Start FFmpeg hourly recordings
	#ffmpeg 
	#ffmpeg -stimeout 2000 \ 
	#ffmpeg -stimeout 300000 \
	ffmpeg -stimeout 1000000 \
	 -abort_on empty_output \
	 -rtsp_transport tcp \
	 -fflags nobuffer \
	 -an \
	 -i rtsp://ip:port/unicast \
	 -map 0:v \
	 -c copy \
	 -metadata title="" \
	 -f segment \
	 -segment_time 600 \
	 -segment_wrap 100 \
	 -reset_timestamps 1 \
	 -strftime 1 \
	 "$BASEDIRECTORY/$YEAR/$MONTH/$DAY/file-%Y%m%d-%H%M.mp4"
	 echo "$(date): 왜 그런진 모르지만, ffmpeg 가 죽어서 재시작!"
done

이제 막 시험해봤으니.. 결과는 오늘 내로 나올테지만, 무한루프로 돌리고 있으니 뭐 어쨌든 소기의 목적은 달성할 수 있으리라 생각한다.

다만, 연결이 끊어지는 순간 순간마다 영상 녹화가 누락되는 상황은 어쩔 수가 없다. (그게 수초에서 길어야 1분 정도일테지만, 그 순간에 뭔 일이 날까봐 녹화를 하는건데..)
이 부분이 조금 아쉽다.

그건 어쩔 수 없다 치고, 시험해보고 별 문제가 없다면, 이제 systemd 로 만들어 서비스화하는 작업만 해주면 녹화 시스템에 문제가 생기거나 정기 재부팅을 하더라도 자동으로 재시동되도록 해줄 수 있겠다.

오픈 소스가 이래서 좋긴 한데, 어쨌든 한계는 또 명확하고..
완벽하게 하려면, 돈 들여 제대로된 장비를 들여야겠지.
허나, 거의 돈을 들이지 않고도 이만큼이라도 할 수 있다는게 어딘지.

** 새 명령.

ffmpeg 나, 코덱, 영상에 대한 이해가 전혀 없이 그냥 주먹구구로 하니 답답하기 그지 없는데..
hls 라는 방식을 쓰면, 영상을 정해진 시간에 맞게 잘라서(이걸 segment 라 하는 듯 한데) 저장할 수 있다.
또, 위에선 의미와 기능을 정확히 알지 못하는 선택사항들을 많이 썼는데, 여기선 그냥 아는 내용만을 넣었다.

while :
do
# map 0:v 는 오디오는 제외하라는 명령..
	ffmpeg -rtsp_transport tcp \
	 -i rtsp://주소.. \
	 -map 0:v \
	 -c copy \
	 -metadata title="" \
	 -strftime 1 -strftime_mkdir 1 -hls_time 120 -hls_segment_filename "$BASEDIRECTORY/$YEAR/$MONTH/$DAY/file-%Y%m%d-%H%M.mp4" out.m3u8 | systemd-cat -p info
	 echo "$(date): 왜 그런진 모르지만, ffmpeg 가 죽어서 재시작!"
done

hls 를 선택해야 strftime_mkdir 도 작동한다.
나머지에 대해서도 간단히 설명을 덧붙여본다. 자세하다면 자세한, 영어로된 설명은 위에 FFmpeg Document 에 있다. (봐도 뭔 말인지 이해가 안되는게 문제)

  • -strftime 1 : 뒤에 %Y 등을 쓰기 위해.
  • -strftime_mkdir 1 : 이러면, 파일명에 디렉토리(경로명)가 표기돼 있고, 이 디렉토리가 없을 경우 만들어준다.
  • -hls_time 120 : 초 단위로 영상 파일을 끊어 저장해준다. 120 이면 120초.
  • -hls_segment_filename : 이걸 해줘야 hls 방식을 쓸 수 있는 모양인데.. (확실치 않음)

그런데.. 역시 큐비트럭에선 녹화가 원활하질 못하다. 뭔가 설정이 더 필요한데..
게다가 이렇게 했더니, while 안에서도 조금 문제가 생긴다. 왜..?? (원인 탐색 중!)


여기 저기 뒤져보고, 문의도 해봤지만, 내가 원하는 답을 찾지는 못했다.
그래도, 이리 저리 뒤진 결과로, 대충 결과는 낼 수 있게 됐다.

위 명령대로 ffmpeg 를 실행하면, 중간 중간 끊기는 현상이 발생한다. 서버, 즉 Dafang 카메라의 문제로 보이는데, 이걸 현재 상황으로(물론 내 수준에서) 해결할 방법이 없다. 수많은 ffmpeg 의 옵션을 적절히 조합하면 될 수도 있을 듯 한데.. 관련 지식이 없다보니 어쩔 도리가 없다.

무한 영역으로!

위에도 적었지만, 내가 생각한 대안은 무한 루프였다. ffmpeg 를 돌리되, ‘멈춤 현상’을 인정하고, 그걸 프로그램으로 해결한다.
최종 결과는 다음과 같다.

#!/usr/bin/bash

BASEDIRECTORY="$HOME/카메라 녹화"

YEAR=$(date +"%Y");
MONTH=$(date +"%m");
DAY=$(date +"%d");

mkdir -p "$BASEDIRECTORY/$YEAR/$MONTH/$DAY"


# 자꾸 죽는 현상을 대비해 무한루프로.

while :
do
	ffmpeg -stimeout 2000 \
	 -abort_on empty_output \
	 -rtsp_transport tcp \
	 -an \
	 -i rtsp://ip:port \
	 -map 0:v \
	 -b:v 800k \
	 -bufsize 600k \
	 -r 24 \
	 -c copy \
	 -metadata title="" \
	 -f segment \
	 -segment_time 300 \
	 -reset_timestamps 1 \
	 -strftime 1 \
	 "$BASEDIRECTORY/$YEAR/$MONTH/$DAY/file-%Y%m%d-%H%M.mp4" | systemd-cat -p info	
	 echo "$(date): 왜 그런진 모르지만, ffmpeg 가 죽어서 재시작!"

done

while 에만 넣었고, 별다른 변동 사항은 없다. 딱 하나, systemd-cat 을 빼고는.

systemd 에 참가

저 스크립트의 한가지 문제점은, 바로 날짜, 그리고 그 날짜에 입각한 디렉토리 생성에 있다. 오류가 발생하지 않는다고 가정하면, 모든 파일은 스크립트를 처음 실행한 날짜의 디렉토리 (/home/user/카메라 녹화/2020/10/02/ 등)에 저장된다.

굳이 디렉토리에 날짜를 넣은 이유는, 하루치만큼의 파일을 동일한 디렉토리에 넣어놓고자 함이었는데, 이렇게 되면 의도와는 전혀 다른 결과를 받게 된다. (물론, 수시로 ffmpeg 가 알아서(?) 죽기 때문에 그럴 염려는 안해도 되지만..)

아무튼, 원래 의도대로 하루치 파일을 한 디렉토리에 넣어놓으려면, 매일 밤 12:00 에 저 스크립트를 시작해줘야 한다. 매번 수동으로 돌려줘도 물론 된다.(그러려면 tmux 등을 써야만 한다.)

하지만 그럴 수는 없는 터. 자동!하면 생각나는게 cron/crontab 인데, 매일 특정 시간에 실행되게끔 할 수는 있다. 예를 들어, 매일 밤 12:00 에 실행되게끔.

그러나 여기도 문제가 있다. 만약, 뭔가 일이 있어서 시스템 재부팅을 했을 경우, 저 스크립트는 밤 12시가 되기 전까진 다시 시작되지 않는다. 따라서, systemd 를 이용하여, 시스템이 시작될 때, 자동으로 실행되게끔 만들어야 한다.

/etc/systemd/system/cctv-record.service 를 만들고, 다음과 같은 내용을 넣는다.

[Unit]
Description=Dafang Cam record
Wants=network.target
After=network-online.target

[Service]
User=username
Group=groupname
Type=simple
ExecStart=/home/username/bin/cctv-rec.sh
Restart=on-failure
RestartSec=10
KillMode=process

[Install]
WantedBy=multi-user.target

User/Group 은 넣지 않아도 된다. 그러면 root 권한으로 실행이 되고, 이 스크립트로 생성된 파일도 역시 root 소유가 된다. 이를 방지하고자 User/Group 을 넣어줬다.
혹은, 아예 이 파일을 개인영역에 만들고 사용자 권한으로 실행하게끔 할 수도 있긴 하다.

ExecStart 도 그냥 /home 경로를 사용했는데, 보통은 전역(/usr/local/bin/ 등)으로 복사를 해놓는 편이다.

이 내용은 MCKAY 선생님의 도움을 받아 작성할 수 있었다.

마지막으로 enable and start.

sudo systemctl enable --now cctv-record.service

systemd 와 journal 을 위해서, 원 스크립트의 마지막에 | systemd-cat -p info 를 넣었다. 이로 인해, journalctl 에서 cctv 스크립트의 문구를 볼 수 있게 된다.

crontab 으로, 매일 자정에 재시작

cctv-record 서비스만 재시작하게 할 수도 있지만(systemd restart cctv-record), 그냥 기기 자체를 매일 밤에 재부팅하게끔 했다. 그러면 서비스도 당연히 재시작되고, 새로운 날짜에 새 디렉토리가 자연스레 만들어진다.

….

썩 맘에 들진 않지만, 이걸로 당분간은 만족하는 수밖에.

Author: 아무도안

3 thoughts on “꽃삽질 : ffmpeg 를 이용한 rtsp stream 녹화

  1. crontab으로 자정에 재시작 하는 대신에
    ffmpeg 옵션중에서 -strftime_mkdir 옵션을 이용하면 ffmpeg에서 자동으로 폴더를 만들어줍니다.

    저도 ffmpeg가 왠지 모르게 자꾸 죽는… 문제가 생기는데 비슷한 방법으로 일단 만족중인데…
    도무지 왜 죽는지 모르겟네요 ㅠㅠ

    1. 고맙습니다. strftime_mkdir 은 이렇게 쓰는 모양이군요. https://ffmpeg.org/ffmpeg-formats.html#Options-5 에 내용이 나와 있었네요.

      strftime_mkdir
      Used together with -strftime_mkdir, it will create all subdirectories which is expanded in filename.

      나중에 이대로 적용해봐야겠습니다.

      Dafang Custom Firmware 에 문의한 내용에 어떤 분이 답을 달아주셨는데요. 아마도 기기(하드웨어)의 한계로 보인다는 의견을 주셨습니다.
      이 정도 가격대 기기에서는 그 정도는 감수해야 한다는 뜻으로 보입니다.

  2. -strftime_mkdir 1 을 넣고 해봤는데, 디렉토리/파일 생성이 되질 않는군요.
    저 위 스크립트에서 -strftime 1 \ 다음에 넣어봤는데, 파일이 없다는 오류가 발생합니다.
    뭔가 다른 방법이 있는 모양인데, 검색해봐도 없어서~ ㅎㅎ
    그냥 이전으로 복귀했습니다.


    2021.05.04 추가

    이게 작동하려면, hls 를 택해야 합니다.

안녕하세요. 글 남겨주셔서 고맙습니다.