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

** 21.05.10
정말 최종판은 또 다른 글에..


이 글로 이 삽질의 끝을 볼 수 있기 바라며.. (하루 정도 시험해봤는데, 죽지 않는다. CPU 점유율도 4% 내외. 이 정도면 성공이다.)

** 추가
죽지는 않는데, 이런 오류가 발생한다.

segment @ 0x18793d0] Non-monotonous DTS in output stream 0:0; previous: 610070715, current: -766982; changing to 610070716. This may result in incorrect timestamps in the output file.
.....

이게 계속 이어지면서 세그먼트 파일은 2분 분할이 되지 않고, 점점 커지는 현상이 생긴다.
그냥 죽어버리면 차라리 나은데..
이 문제는 현재 다른 글에서 연구 중이다.


두 번에 걸쳐 이와 관련된 글을 썼었다.

그러나, 둘 모두 실패했다.
첫번째는 실패라고 하긴 좀 그렇지만, 그렇다고 원활하게 돌아간다고 말하기도 어렵다.
두번째, openRTSP 는 완전히 실패였다. 원인은 파악 불가.

그러다가, openRTSP 에 관해 도움을 얻었던 글의 다른 항목에서 ffmpeg 를 좀 다르게 사용하는 법에 대해 알게 되었다.
그 내용을 정리해본다.

ffmpeg -fflags +igndts \
        -i rtsp://주소 \
        -vcodec copy \
        -map 0:v \
        -metadata title="스트리밍 영상 녹화" \
        -f segment \
        -reset_timestamps 1 \
        -break_non_keyframes 1 \
        -segment_time 120 \
        -write_empty_segments 1 \
        -segment_format mp4 \
        -strftime 1 \
        "$BASEDIRECTORY/$YEAR/$MONTH/$DAY/dadcam-%Y%m%d-%H%M.mp4"

아직은 짧은 시간(1시간쯤?)동안 지켜본 상태지만, 적어도 다른 두가지 방식보다는 안정성이 있어 보인다.

rtsp 서버에서 보내는 영상은 1280*720/24fr 인데, 위 명령으로는 ‘영상’만 기록할 수 있다. 음성이 필요하다면, 아마도 -c copy -map 0 으로 바꾸면 될 듯하다.
2분 기준, 파일 크기는 약 38MB 정도 나온다. 좀 큰 듯은 한데 더 줄일 수 있는 방법은 못 찾겠다.

위 선택사항들에 관한 설명은 ffmpeg Documents 에서 모두 찾아볼 수 있지만.. 봐도 뭔 내용인지 알기가 어렵다는데에, 나로 하여금 이 꽃삽질을 하게끔 만든 원인이 있다.
아무튼, 대충 알아낸 대로만 적어본다.

  • rtsp://주소 : 동영상 서버의 주소를 넣는다.
  • -vcodec copy : rtsp 에서 송출되는 영상을 그대로 복사한다. Transcode 를 하지 않는다는 의미.
  • -f segment : 영상을 분할하여 저장한다.
  • -segement_time 120 : 영상을 몇 초 단위로 저장할 지 지정. (120초이므로 2분 간격)
  • -write_empty_segments 1 : 입력되는 패킷이 없더라도 빈 segment 파일을 작성한다.
  • -segment_format mp4 : 동영상을 mp4 형식으로 저장한다.
  • -strftime 1 : 파일명에 %Y 등 형식을 쓸 수 있게 한다.

strftime_mkdir 은, hls 를 썼을 때만 가능하다. 디렉토리를 만들어야 한다면, 스크립트에서 작업을 해줘야 한다. 따라서 여기서는 사용하지 않았다.

지난 번과 비교해서 가장 큰 차이라면, segment_format, write_empty_segments 정도일텐데, 이게 그렇게 큰 차이를 만들어냈으려나??
또, 지난 번엔 segment_time 을 600 초로, 다소 크게 잡았었는데, 이번엔 2분으로 낮췄다. 물론, segments 간 녹화가 중간에 비는 상황은 없다. 이전 파일이 다음 파일로 바로 이어진다는 얘기. (이전 파일이 1:05:41 초에 끝났다면, 다음 파일은 바로 그 다음으로 이어진다.)

그리고.. 아직 이런 일은 없었지만, 혹시나 ffmpeg 가 이유없이 죽을 경우를 대비해서 무한 루프를 활성화 한다.

** 추가한 설정

  • -fflags +igndts : Non-monotonous DTS 오류를 방지하기 위해. 아직 효과가 있는지는 확인하지 못했다.
  • -reset_timestamps 1 : 각 세그먼트 별로 타임스탬프를 0 에서 시작하게 한다.
  • -break_non_keyframes 1 : 영상 재생 시에 시간을 탐색이 원활하지 못한 문제를 해결하기 위해.

Non-monotonous DTS 관련 오류가 발생하여 찾아보니, 저걸 넣으라고 한다. 하지만, 여전히 오류가 난다는 내용도 같이 써있다.
저게 뭔지는, 어쩐지 찾아보고 나면 짜증만 더 날 듯 하여 일부러 찾아보지 않았다. 아무튼, 일단은 시험해보기로 한다.

reset_timestamps 와 break_non_keyframes 는 파일 재생 시 탐색을 잘 할 수 있게 하기 위함인데, 아마도 reset_timestamps 만 넣어줘도 되지 않을까한다. 안해봐서 장담은 못하겠지만.
게다가, break_non_keyframes 의 설명항목을 보면 오히려 안좋은 결과가 나올 수도 있다고 한다. (If enabled, allow segments to start on frames other than keyframes. This improves behavior on some players when the time between keyframes is inconsistent, but may make things worse on others, and can cause some oddities during seeking.)

일단은 넣어보고.. 또 문제가 생기면 바꿔보기로.

무한 영역으로!

#!/usr/bin/bash
BASEDIRECTORY="/카메라 녹화"
YEAR=$(date +"%Y");
MONTH=$(date +"%m");
DAY=$(date +"%d");

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

while :
do
  ffmpeg -fflags +igndts \
        -i rtsp://주소 \
        -vcodec copy \
        -map 0:v \
        -metadata title="스트리밍 영상 녹화" \
        -f segment \
        -reset_timestamps 1 \
        -break_non_keyframes 1 \
        -segment_time 120 \
        -write_empty_segments 1 \
        -segment_format mp4 \
        -strftime 1 \
        "$BASEDIRECTORY/$YEAR/$MONTH/$DAY/dadcam-%Y%m%d-%H%M.mp4"

  echo "$(date): 왜 그런진 모르지만, ffmpeg 가 죽어서 재시작!" >> "$BASEDIRECTORY/$YEAR/$MONTH/$DAY/cctv.log"
done

그리고, 이것을 systemd 로 자동 재시작되게끔 한다.

systemd 에 참가

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 스크립트의 문구를 볼 수 있게 된다.

frame rate 조절??

fps 조절이 되긴 된다. 그러면 용량도 꽤 주는데, 영상 자체는 당연히 좀 이상해지고, 시간도 제대로 계산하지 못하게 된다. 이건 원래 이런 건지, 오류가 발생해서 이런 건지는 모르겠다. 즉, 2분 녹화를 했지만, 20분이라고 나온다든가.
또는, 영상을 앞/뒤로 빨리 돌려보기가 안된다든가 하는 문제도 있다.

아무튼, 하고 싶다면 -vcodec copy 를 빼고, -vf fps=fps=5 등을 넣는다.

….

새로운 디렉토리 생성을 위해서 매일 자정에 재시작하도록 cron 작업을 해줄 필요가 있다.
재부팅을 하든지, 아니면 systemd 를 재시작 하도록 하든지.

이걸로 잘 될 수 있기를..

아무도안아무도안
Author: 아무도안

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