ffmpeg录制转发mediasoup的音视频流

0.前言

在上一篇章讲述了,如何使用ffmpeg推送本地流到mediasoup(https://blog.csdn.net/qq_15559817/article/details/115698060?spm=1001.2014.3001.5501
本章讲述下如何使用ffmpeg录制mediasoup产生的音视频rtp流

想要从mediasoup服务器拉流,主要通过调用demo提供的API接口,先加入房间然后创建rtp对应的消费者,然后根据Consumer的参数构造sdp文件,再使用ffmpeg进行拉取录制保存。

具体的操作实现过程都放在shell脚本里面,以及ffmpeg执行的命令。

1.通过ffmpeg消费mediasoup的音频流

拉取音频流的脚本如下,使用时需将SERVER_URL、ROOM_ID、PRODUCER_ID和MEDIA_FILE改成对应的数值

#!/usr/bin/env bash

SERVER_URL=https://192.168.12.90:15025
ROOM_ID=1dzuyv8o
PRODUCER_ID=0332cab6-9e28-4a4b-9563-90494b9d1aaf
MEDIA_FILE=./output/res_audio.opus

function show_usage()
{
	echo
	echo "USAGE"
	echo "-----"
	echo
	echo "  SERVER_URL=https://my.mediasoup-demo.org:4443 ROOM_ID=test PRODUCER_ID=c4a1ed8b-0d71-422d-a9c0-7fed44bf05bc"
	echo
	echo "  where:"
	echo "  - SERVER_URL is the URL of the mediasoup-demo API server"
	echo "  - ROOM_ID is the id of the mediasoup-demo room (it must exist in advance)"
	echo
	echo "REQUIREMENTS"
	echo "------------"
	echo
	echo "  - ffmpeg: stream audio and video (https://www.ffmpeg.org)"
	echo "  - httpiei: command line HTTP client (https://httpie.org)"
	echo "  - jq: command-line JSON processor (https://stedolan.github.io/jq)"
	echo
}

echo

if [ "$(command -v ffmpeg)" == "" ] ; then
	>&2 echo "ERROR: ffmpeg command not found, must install FFmpeg"
	show_usage
	exit 1
fi

if [ "$(command -v http)" == "" ] ; then
	>&2 echo "ERROR: http command not found, must install httpie"
	show_usage
	exit 1
fi

if [ "$(command -v jq)" == "" ] ; then
	>&2 echo "ERROR: jq command not found, must install jq"
	show_usage
	exit 1
fi

set -e

BROADCASTER_ID=$(LC_CTYPE=C tr -dc A-Za-z0-9 < /dev/urandom | fold -w ${1:-32} | head -n 1)
HTTPIE_COMMAND="http --check-status --verify=no"


#
# Verify that a room with id ROOM_ID does exist by sending a simlpe HTTP GET. If
# not abort since we are not allowed to initiate a room..
#
echo ">>> verifying that room '${ROOM_ID}' exists..."

res=$(${HTTPIE_COMMAND} \
	GET ${SERVER_URL}/rooms/${ROOM_ID} \
	2> /dev/null)

#
# Create a Broadcaster entity in the server by sending a POST with our metadata.
# Note that this is not related to mediasoup at all, but will become just a JS
# object in the Node.js application to hold our metadata and mediasoup Transports
# and Producers.
#
echo ">>> creating Broadcasters ..."

${HTTPIE_COMMAND} \
	POST ${SERVER_URL}/rooms/${ROOM_ID}/broadcasters \
	id="${BROADCASTER_ID}" \
	displayName="Broadcaster" \
	device:='{"name": "recorder"}' \
	rtpCapabilities:=${res} \
	> /dev/null

#
# Upon script termination delete the Broadcaster in the server by sending a
# HTTP DELETE.
#
trap 'echo ">>> script exited with status code $?"; ${HTTPIE_COMMAND} DELETE ${SERVER_URL}/rooms/${ROOM_ID}/broadcasters/${BROADCASTER_ID} > /dev/null' EXIT


#
# Create a PlainTransport in the mediasoup to pull  video using plain RTP
# over UDP. Do it via HTTP post specifying type:"plain" and comedia:false and
# rtcpMux:false.
#
echo ">>> creating mediasoup PlainTransport for consumer audio..."

res=$(${HTTPIE_COMMAND} \
	POST ${SERVER_URL}/rooms/${ROOM_ID}/broadcasters/${BROADCASTER_ID}/transports \
	type="plain" \
	comedia:=false \
	rtcpMux:=true \
	2> /dev/null)

#
# Parse JSON response into Shell variables and extract the PlainTransport id,
# IP, port and RTCP port.
#
eval "$(echo ${res} | jq -r '@sh "transportId=\(.id) transportIp=\(.ip) transportPort=\(.port) transportRtcpPort=\(.rtcpPort)"')"

# echo ${res}


echo ">>> PlainTransport Connect ..."

${HTTPIE_COMMAND} -v \
	POST ${SERVER_URL}/rooms/${ROOM_ID}/broadcasters/${BROADCASTER_ID}/transports/${transportId}/plainconnect \
	ip="127.0.0.1" \
	port:=30010 \
	rtcpport:=30011 \
	> /dev/null


echo ">>> creating mediasoup audio consumer..."

res1=$(${HTTPIE_COMMAND} \
	POST ${SERVER_URL}/rooms/${ROOM_ID}/broadcasters/${BROADCASTER_ID}/transports/${transportId}/consume?producerId=${PRODUCER_ID} \
		2> /dev/null)


# echo "creat consumer res :"
# echo ${res1}
eval "$(echo ${res1} | jq -r '@sh "consumeId=\(.id)"')"

echo ">>> resume ..."
# echo ${consumeId}

${HTTPIE_COMMAND} -v \
	POST ${SERVER_URL}/rooms/${ROOM_ID}/broadcasters/${BROADCASTER_ID}/consume/${consumeId}/resume \
		> /dev/null


echo ">>> running ffmpeg..."

ffmpeg -max_delay 5000 -reorder_queue_size 20000 -protocol_whitelist "file,udp,rtp" -i audio.sdp -acodec aac -y ./output/res_audio.aac
# ffmpeg -thread_queue_size 512 -protocol_whitelist "file,udp,rtp" -i audio.sdp -acodec copy -y ${MEDIA_FILE}
# ffmpeg -protocol_whitelist "file,udp,rtp" -i audio.sdp -acodec copy -f rtp_mpegts rtp://192.168.12.90:10000

audio.sdp文件内容如下:

v=0
o=- 0 0 IN IP4 127.0.0.1
s=ffmpeg
c=IN IP4 192.168.12.90
t=0 0
a=tool:libavformat 58.26.101
m=audio 30010 RTP/AVP 100
a=rtpmap:100 opus/48000/2
a=fmtp:100 sprop-stereo=1
a=sendonly

2.通过ffmpeg消费mediasoup的视频流

#!/usr/bin/env bash

SERVER_URL=https://192.168.12.90:15025
ROOM_ID=0fmkkzxl
PRODUCER_ID=c77e8b4b-98c7-4e20-b519-566053d79fad
MEDIA_FILE=./output/res_video.webm

function show_usage()
{
	echo
	echo "USAGE"
	echo "-----"
	echo
	echo "  SERVER_URL=https://my.mediasoup-demo.org:4443 ROOM_ID=test PRODUCER_ID=c4a1ed8b-0d71-422d-a9c0-7fed44bf05bc"
	echo
	echo "  where:"
	echo "  - SERVER_URL is the URL of the mediasoup-demo API server"
	echo "  - ROOM_ID is the id of the mediasoup-demo room (it must exist in advance)"
	echo
	echo "REQUIREMENTS"
	echo "------------"
	echo
	echo "  - ffmpeg: stream audio and video (https://www.ffmpeg.org)"
	echo "  - httpiei: command line HTTP client (https://httpie.org)"
	echo "  - jq: command-line JSON processor (https://stedolan.github.io/jq)"
	echo
}

echo


if [ "$(command -v ffmpeg)" == "" ] ; then
	>&2 echo "ERROR: ffmpeg command not found, must install FFmpeg"
	show_usage
	exit 1
fi

if [ "$(command -v http)" == "" ] ; then
	>&2 echo "ERROR: http command not found, must install httpie"
	show_usage
	exit 1
fi

if [ "$(command -v jq)" == "" ] ; then
	>&2 echo "ERROR: jq command not found, must install jq"
	show_usage
	exit 1
fi

set -e

BROADCASTER_ID=$(LC_CTYPE=C tr -dc A-Za-z0-9 < /dev/urandom | fold -w ${1:-32} | head -n 1)
HTTPIE_COMMAND="http --check-status --verify=no"
VIDEO_SSRC=128827720
VIDEO_PT=101


#
# Verify that a room with id ROOM_ID does exist by sending a simlpe HTTP GET.
# If not abort since we are not allowed to initiate a room..
#
echo ">>> verifying that room '${ROOM_ID}' exists..."

res=$(${HTTPIE_COMMAND} \
	GET ${SERVER_URL}/rooms/${ROOM_ID} \
	2> /dev/null)

#
# Create a Broadcaster entity in the server by sending a POST with our metadata.
# Note that this is not related to mediasoup at all, but will become just a JS
# object in the Node.js application to hold our metadata and mediasoup Transports
# and Producers.
#
echo ">>> creating Puller..."

${HTTPIE_COMMAND} \
	POST ${SERVER_URL}/rooms/${ROOM_ID}/broadcasters \
	id="${BROADCASTER_ID}" \
	displayName="Broadcaster" \
	device:='{"name": "recorder"}' \
	rtpCapabilities:=${res} \
	> /dev/null

#
# Upon script termination delete the Broadcaster in the server by sending a
# HTTP DELETE.
#
trap 'echo ">>> script exited with status code $?"; ${HTTPIE_COMMAND} DELETE ${SERVER_URL}/rooms/${ROOM_ID}/broadcasters/${BROADCASTER_ID} > /dev/null' EXIT

#
# Create a PlainTransport in the mediasoup to pull  video using plain RTP
# over UDP. Do it via HTTP post specifying type:"plain" and comedia:false and
# rtcpMux:false.
#
echo ">>> creating mediasoup PlainTransport for consumer video..."

res=$(${HTTPIE_COMMAND} \
	POST ${SERVER_URL}/rooms/${ROOM_ID}/broadcasters/${BROADCASTER_ID}/transports \
	type="plain" \
	comedia:=false \
	rtcpMux:=true \
	2> /dev/null)

#
# Parse JSON response into Shell variables and extract the PlainTransport id,
# IP, port and RTCP port.
#
eval "$(echo ${res} | jq -r '@sh "transportId=\(.id) transportIp=\(.ip) transportPort=\(.port) transportRtcpPort=\(.rtcpPort)"')"



echo ">>> PlainTransport Connect ..."

${HTTPIE_COMMAND} -v \
	POST ${SERVER_URL}/rooms/${ROOM_ID}/broadcasters/${BROADCASTER_ID}/transports/${transportId}/plainconnect \
	ip="127.0.0.1" \
	port:=30000 \
	rtcpport:=30001 \
	> /dev/null

#echo ${res}


echo ">>> creating mediasoup video consumer..."

res1=$(${HTTPIE_COMMAND} \
	POST ${SERVER_URL}/rooms/${ROOM_ID}/broadcasters/${BROADCASTER_ID}/transports/${transportId}/consume?producerId=${PRODUCER_ID} \
		2> /dev/null)

echo "creat consumer res :"
echo ${res1}
eval "$(echo ${res1} | jq -r '@sh "consumeId=\(.id)"')"

echo ">>> resume ..."
# echo ${consumeId}

${HTTPIE_COMMAND} -v \
	POST ${SERVER_URL}/rooms/${ROOM_ID}/broadcasters/${BROADCASTER_ID}/consume/${consumeId}/resume \
		> /dev/null


echo ">>> request keyFrame..."

${HTTPIE_COMMAND} -v \
	POST ${SERVER_URL}/rooms/${ROOM_ID}/broadcasters/${BROADCASTER_ID}/consume/${consumeId}/requestKeyFrame \
		> /dev/null



echo ">>> running ffmpeg..."

ffmpeg -thread_queue_size 1024 -protocol_whitelist "file,udp,rtp" -i video.sdp -vcodec copy -y ${MEDIA_FILE}
# ffmpeg -thread_queue_size 1024 -protocol_whitelist "file,udp,rtp" -i video.sdp -vcodec h264 -y output.mp4
# ffmpeg -protocol_whitelist "file,udp,rtp" -i video.sdp -vcodec copy -f rtp_mpegts rtp://192.168.12.90:10000

video.sdp的文件内容如下:

v=0
o=- 0 0 IN IP4 127.0.0.1
s=ffmpeg
c=IN IP4 192.168.12.90
t=0 0
m=video 30000 RTP/AVPF 101 102
a=rtpmap:101 VP8/90000
a=rtpmap:102 rtx/90000
a=fmtp:102 apt=101d
a=extmap:4 urn:3gpp:video-orientation
a=setup:active
a=mid:1
a=sendrecv

通过以上操作,便可以用ffmpeg通过dump下rtp流进行保存录制,也可以将rtp流转发到其他服务器。

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

orgotF

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值