WinGyu_coder
Python, 파이썬으로 실시간 스트리밍 구현하기, RTMP, FFmpeg 사용 방법 본문
Python 개발자로 일을 하다가 보니, 영상 분석쪽 업무를 하게 되었는데 분석한 영상을 스트리밍으로 구현을 해야 했다.
그러기 위해 Cloudflare CDN 서버를 사용했는데, 나쁘지 않게 구현이 가능해서 글을 적어본다.
간단한 구성은 아래와 같다.
설명해보자면 우선 우분투 리눅스로 서버를 구성하였다.
사용자가 영상 분석을 요청하면 HTTP, HTTPS 요청을 서버가 받아서 영상 분석을 시작한다.
들어온 요청 만큼 파이썬이 FFmpeg 프로세서 명령어를 실행해 영상을 RTMP 를 통해 CDN 서버인 Cloudflare에 보낸다.
아무래도 실시간 스트리밍이기 때문에 실시간 영상 분석 속도가 관건이다. (전송속도 및 영상 재생 속도가 문제 있을시 FPS 및 해상도를 조절해보자, 영상 코덱, 전송 통신, 네트워크 등 생각해야할게 너무 많았다)
우선 Cloudflare 에 대해 알아보자.
https://www.cloudflare.com/ko-kr/
간단히 설명하면 클라우드 서버를 운영하는 곳이다. CDN 서버를 지원한다.
영상 스트리밍 서비스도 지원을 해주고 각종 보안, 도메인, 웹 등을 지원한다.
cloudflare 는 개발자를 위한 문서뿐 아니라 일반 방송인, 관련 업종 종사자도 할 수 있게 구성을 해두었다.
우리는 Cloudflare를 영상 스트리밍 서버로 사용할거다.
(비용이 생기니 잘 알아보고 사용하자, 나름 합리적이고 저렴하다)
Django 랑 Nginx 설명은 넘어가겠다
가장 중요한 FFmpeg 이다.
영상 스트리밍에 대해 다양한 종류 및 형태로 기록하고 변환해주는 SW 소프트웨어 이다.
자유 소프트웨어와 오픈 소스로 구성되어 있다.
윈도우, 맥, 리눅스 등 전부 지원한다.
위 사이트를 접속해보면 아주 대단한 예시를 볼 수 있다.
위 명령어만 치면 영상 확장자를 변환할 수 있다.
자 그러면 필자가 구성한 리눅스 서버에 이를 설치해보자.
sudo apt update
sudo apt install ffmpeg
ffmpeg -version
아주 설치가 간단하다. 위 설치 명령어 후 ffmpeg -version 으로 버전을 확인해보자.
설치가 완료 되었으면 이를 사용할 파이썬 소스 코드다.
subprocess 라는 라이브러리를 사용했다.
import cv2
import numpy as np
import torch
from time import time
import subprocess
from ultralytics import YOLO
from ultralytics.utils.plotting import Annotator, colors
model_path = "weights/yolov8n-pose.pt"
video_path = "uploads/20240108_112946.mp4"
class ObjectDetection:
# 초기화
def __init__(self):
self.model= YOLO(model_path)
self.classes = self.model.names
def draw_frame(self, frame):
results = self.model.track(frame, persist=True)
if results[0].boxes.id is not None:
# Get the boxes and track IDs
boxes = results[0].boxes.xywh.cpu()
track_ids = results[0].boxes.id.int().cpu().tolist()
clss = results[0].boxes.cls.cpu().tolist()
annotator = Annotator(frame, line_width=2, example=str(self.classes))
for r in results:
if r.keypoints is not None:
for k in reversed(r.keypoints.data):
annotator.kpts(k, r.orig_shape, radius=5, kpt_line=True)
for box, track_id, cls in zip(boxes, track_ids, clss):
if isinstance(box, torch.Tensor):
box = box.tolist()
x, y, w, h = box[0], box[1], box[2], box[3]
w_half = w / 2
h_half = h / 2
box = [x - w_half, y - h_half, x + w_half, y + h_half]
# draw 기능, 하지만 좌표 에러남. 위 bbox 재정의로 해결
annotator.box_label(box, str(self.classes[cls]), color=colors(cls, True))
return frame
od = ObjectDetection()
cap = cv2.VideoCapture(video_path)
private_ip = "192.168.주소.주소"
rtmp_out_url = "rtmps://live.cloudflare.com:443/live/"
key="cloudflare 키값"
make_url = rtmp_out_url + key
fps = int(cap.get(cv2.CAP_PROP_FPS))
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
command = ['ffmpeg',
'-y',
'-f', 'rawvideo',
'-vcodec', 'rawvideo',
'-pix_fmt', 'bgr24',
'-s', "{}x{}".format(1280, 720),
'-r', str(15),
'-i', '-',
'-c:v', 'libx264',
'-pix_fmt', 'yuv420p',
'-preset', 'ultrafast',
'-f', 'flv',
'-b:v', '2000k',
"-acodec", "aac",
"-b:a", "128k",
"-flvflags", "no_duration_filesize",
make_url]
# using subprocess and pipe to fetch frame data
p = subprocess.Popen(command, stdin=subprocess.PIPE)
while cap.isOpened():
# start_time = time()
status, frame = cap.read()
if not status:
break
# results=od.score_frame(frame)
# frame=od.mosaic_frame(results,frame)
frame = od.draw_frame(frame)
frame = cv2.resize(frame, (1280, 720))
p.stdin.write(frame.tobytes())
# 'q' 입력시 웹캠 종료
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
cv2.waitKey(1)
위 소스 코드는 ultralytics 에서 만든 yolov8을 통해 키포인트 인식 하는 소스 코드다.
가장 중요한 코드는 이거다.
rtmp_out_url = "rtmps://live.cloudflare.com:443/live/"
key="cloudflare 키값"
make_url = rtmp_out_url + key
fps = int(cap.get(cv2.CAP_PROP_FPS))
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
command = ['ffmpeg',
'-y',
'-f', 'rawvideo',
'-vcodec', 'rawvideo',
'-pix_fmt', 'bgr24',
'-s', "{}x{}".format(1280, 720),
'-r', str(15),
'-i', '-',
'-c:v', 'libx264',
'-pix_fmt', 'yuv420p',
'-preset', 'ultrafast',
'-f', 'flv',
'-b:v', '2000k',
"-acodec", "aac",
"-b:a", "128k",
"-flvflags", "no_duration_filesize",
make_url]
cloudflare에서 받은 rtmp 주소와 키 값을 적어준다.
그리고 FFmpeg에서 사용할 명령어를 위 command 처럼 정해준다.
사용할 환경에 따라 명령어를 검색해서 수정해주면 된다.
그리고 마지막엔 rtmp 주소를 적으면 된다. (make_url) 부분
p = subprocess.Popen(command, stdin=subprocess.PIPE)
while cap.isOpened():
# start_time = time()
status, frame = cap.read()
if not status:
break
# results=od.score_frame(frame)
# frame=od.mosaic_frame(results,frame)
frame = od.draw_frame(frame)
frame = cv2.resize(frame, (1280, 720))
p.stdin.write(frame.tobytes())
# 'q' 입력시 웹캠 종료
if cv2.waitKey(10) & 0xFF == ord('q'):
break
이제 subprocess 를 사용해 실행해주면 분석한 영상을 실시간으로 스트리밍 및 스트리밍이 가능하다.
'Python파이썬' 카테고리의 다른 글
Ubuntu Linux Python version solution, pyenv 우분투 리눅스 20.04에서 Python 파이썬 버전 관리하기 (0) | 2024.07.04 |
---|---|
Python CV 컴퓨터 비전, 다각형 그리기 및 접근 여부 알아내기 (0) | 2023.11.16 |
Python, 파이썬 3개의 점 좌표에 대한 각도 구하기, 모듈 math 사용하기 (0) | 2023.11.08 |
Python 난독화 및 암호화, Pyarmor 사용하기 (유료버전) (2) | 2023.10.10 |
Django 파일 업로드 DRF, parser_classes (0) | 2023.10.01 |