76 lines
2.6 KiB
Python
76 lines
2.6 KiB
Python
|
|
import asyncio
|
|
import time
|
|
from app.config import ffmpeg_path, rtmp_url, flv_url
|
|
from app.services.stream_manager import stream_manager
|
|
from app.utils.logger import get_logger
|
|
from app.utils.md5 import generate_md5
|
|
import subprocess
|
|
from urllib.parse import urljoin
|
|
|
|
logger = get_logger(__name__)
|
|
test_url = "rtsp://admin:jitu0818@192.168.4.102:554/Streaming/Channels/101"
|
|
|
|
async def log_output(process, output_url):
|
|
while True:
|
|
output = await asyncio.to_thread(process.stderr.readline)
|
|
if output == "" and process.poll() is not None:
|
|
break
|
|
if output:
|
|
logger.debug(f"ffmpeg output for {output_url}: {output.strip()}")
|
|
if process.returncode != 0:
|
|
logger.error(f"ffmpeg process for {output_url} failed with return code {process.returncode}")
|
|
|
|
|
|
async def start_stream(stream_id: str, output_url: str):
|
|
logger.info(f"Starting stream {stream_id}")
|
|
input_url = test_url # RTSP 流地址
|
|
# 构建 ffmpeg 命令
|
|
command = [
|
|
ffmpeg_path,
|
|
'-i', input_url, # 输入 RTSP 流
|
|
'-c:v', 'libx264', # 视频编码为 libx264
|
|
'-preset', 'ultrafast',
|
|
'-tune', 'zerolatency',
|
|
'-g', '5',
|
|
'-b:v', '6000k', # 码率 6Mbps
|
|
'-r', '30',
|
|
'-b:a', '128k',
|
|
'-c:a', 'aac', # 音频编码为 aac
|
|
'-f', 'flv',
|
|
output_url # 推送到 MediaMTX 流服务
|
|
]
|
|
|
|
# 使用 asyncio.to_thread 异步启动 ffmpeg 进程
|
|
process = await asyncio.to_thread(subprocess.Popen, command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
logger.info(f"ffmpeg command for {stream_id}: {' '.join(command)}")
|
|
|
|
# 异步记录输出
|
|
asyncio.create_task(log_output(process, stream_id))
|
|
|
|
# 保存进程信息
|
|
stream_manager[stream_id] = {
|
|
"process": process,
|
|
"create_time": int(time.time() * 1000)
|
|
}
|
|
return process
|
|
|
|
|
|
async def stream_rtsp_to_flv(stream_id: str):
|
|
md5_route = generate_md5(stream_id)
|
|
output_url = f"{rtmp_url}/{md5_route}"
|
|
# 如果流已经在运行,检查进程是否仍在运行
|
|
if stream_id in stream_manager:
|
|
logger.info(f"Stream {stream_id} is already running.")
|
|
process = stream_manager[stream_id]["process"]
|
|
if process.poll() is None:
|
|
logger.info(f"Stream {stream_id} is still running.")
|
|
return output_url
|
|
# 如果流未在运行,启动新流
|
|
logger.info(f"Stream {stream_id} is not running. Starting new stream.")
|
|
process = await start_stream(stream_id, output_url)
|
|
if process.poll() is None:
|
|
logger.info(f"Stream {stream_id} started successfully.")
|
|
return f"{flv_url}/{md5_route}.flv"
|
|
return None
|