使用树莓派基于FFmpeg推流视频和摄像头到B站直播间
文章目录
- 从B站直播间获取rtmp地址和直播码
- 在终端使用ffpmeg进行视频或摄像头推流
- 用python实现控制树莓派推流
- 如何停止树莓派推流
前提条件
1、首先要有一个树莓派,并连接了摄像头,且能够访问网络。
2、在Bilibili中通过实名认证,并开通了直播间。(很简单的,实名认证通过后直接就可以开通了)。
3、FFmpeg。推流默认使用FFmpeg,树莓派官方系统默认安装FFmpeg了的,可以使用ffpmeg -version查看详细信息。
从B站直播间获取rtmp地址和直播码
申请了B站直播间后,用电脑开启直播,一定要用电脑才能获取rtmp地址和直播码,用手机直播姬开播无法获取rtmp地址和直播码。
点击开始直播后会出现rtmp地址和直播码(如下图),把rtmp地址和直播码拼接起来就是后面ffpmeg推流的地址。
在终端使用ffpmeg进行视频或摄像头推流
以下是树莓派Raspbian系统中推流命令:
#推流USB摄像头(包含音频,音频源为音频文件)
ffmpeg -thread_queue_size 512 -f video4linux2 -s 1280720 -i “视频源” -stream_loop -1 -i “音频源” -vcodec h264_omx -pix_fmt yuv420p -r 30 -s 1280720 -g 60 -b:v 10M -bufsize 10M -acodec aac -ac 2 -ar 44100 -ab 128k -f flv “推流地址”
#推流USB摄像头(包含音频,音频源麦克风)
ffmpeg -thread_queue_size 512 -f video4linux2 -s 1280720 -i “视频源” -i “音频源” -vcodec h264_omx -pix_fmt yuv420p -r 30 -s 1280720 -g 60 -b:v 10M -bufsize 10M -acodec aac -ac 2 -ar 44100 -ab 128k -f flv “推流地址”
#推流USB摄像头(不包含音频)
ffmpeg -thread_queue_size 512 -f video4linux2 -s 1280720 -i “视频源” -vcodec h264_omx -pix_fmt yuv420p -r 30 -s 1280720 -g 60 -b:v 10M -bufsize 10M -an -f flv “推流地址”
#推流视频
ffmpeg -re -i “视频源” -vcodec copy -acodec aac -b:a 192k -f flv “推流地址”
树莓派摄像头推流示例:
ffmpeg -thread_queue_size 512 -f video4linux2 -s 1280720 -i “/dev/video0” -vcodec h264_omx -pix_fmt yuv420p -r 30 -s 1280720 -g 60 -b:v 10M -bufsize 10M -an -f flv “rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_43116538_85852610&key=829133b26b0e1111898aac62df55dcf3&schedul=rtmp”
其中/dev/video0 是树莓派摄像头设备节点,作为推流的输入源,flv 后面那串是B站直播间的rtmp地址加上直播码。
树莓派视频推流示例
ffmpeg -re -i “/home/pi/Desktop/python代码/MP4/video.mp4” -vcodec copy -acodec aac -b:a 192k -flvflags no_duration_filesize -f flv “rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_43116538_85852610&key=829133b26b0e1111898aac62df55dcf3&schedul=rtmp”
以下是Windows系统中推流命令
#推流USB摄像头(包含音频,音频源为音频文件)
ffmpeg -f dshow -s 1280720 -r 1024 -i video=“视频源” -stream_loop -1 -i “音频源” -vcodec libx264 -pix_fmt yuv420p -r 30 -s 1280720 -g 60 -b:v 5000k -acodec aac -ac 2 -ar 44100 -ab 128k -preset:v ultrafast -tune:v zerolatency -f flv “推流地址”
#推流USB摄像头(包含音频,音频源麦克风)
ffmpeg -f dshow -s 1280720 -r 1024 -i video=“视频源” -i “音频源” -vcodec libx264 -pix_fmt yuv420p -r 30 -s 1280720 -g 60 -b:v 5000k -acodec aac -ac 2 -ar 44100 -ab 128k -preset:v ultrafast -tune:v zerolatency -f flv “推流地址”
#推流USB摄像头(不包含音频)
ffmpeg -f dshow -s 1280720 -r 1024 -i video=“视频源” -vcodec libx264 -pix_fmt yuv420p -r 30 -s 1280720 -g 60 -b:v 5000k -an -preset:v ultrafast -tune:v zerolatency -f flv “推流地址”
#推流视频
ffmpeg -re -i “视频源” -vcodec copy -acodec aac -b:a 192k -f flv “推流地址”
以上命令没有经过仔细测试,不同环境需要不同的参数,请自行学习FFmpeg的用法。
FFmpeg基本用法:
ffmpeg [全局选项] {[输入文件选项] -i 输入文件} … {[输出文件选项] 输出文件} …
参数简单介绍:
-f:输入格式(video4linux2 )
-i:输入源
-s:视频分辨率
-r:所需的帧率
-vcodec:视频编解码器
-vb:视频比特率
-bufsize:缓冲区大小(对于流来说很重要)
-vf:像素格式
-g:GOP(图片组,对于流式传输很重要)
-an:不使用音频
-f:输出格式
ffpmeg文档
用python实现控制树莓派推流
上面的推流命令是在树莓派终端执行的,那么如何通过运行python程序来进行摄像头推流呢?
我们可以通过python程序调用sh脚本来执行推流命令。python调用shell脚本的方法有很多种,大家可以自己在网上查,我主要尝试了两种:
一、os.system(“command”)方法
这种方法执行成功会返回一个0。
二、os.popen(“command”)方法
这种方法的返回值是一个文件对象,可以通过read()方法获取返回值。例如:
f=popen("sh ./ffmpeg.sh")
print(f.read())
首先,我们新建一个文件,保存为ffmpeg.sh,然后编辑如下内容,保存:
chmod 777 ./ffmpeg.sh #使脚本具有执行权限
ffmpeg -thread_queue_size 512 -f video4linux2 -s 1280*720 -i "/dev/video0" -vcodec h264_omx -pix_fmt yuv420p -r 30 -s 1280*720 -g 60 -b:v 10M -bufsize 10M -an -f flv "rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_43116538_85852610&key=829133b26b0e1111898aac62df55dcf3&schedul=rtmp"
python调用shell脚本执行推流代码如下:
import os
os.popen("sh /home/pi/Desktop/python代码/ffmpeg/ffmpeg.sh")
如何停止树莓派推流
在尝试用python调用shell脚本进行摄像头推流时,发现了一个问题,就是不知道怎么停止摄像头推流。
摄像头推流不像视频推流,视频推流在把视频推流完后就结束了,但是摄像头推流会一直进行下去,甚至把python代码停止关闭后脚本依然在后台运行,另外,把B站直播间关闭后推流命令仍然在运行,把python程序和B站直播间关闭后,再次打开B站直播间还是能够看到摄像头画面。除非重启树莓派,否则推流指令就会一直在执行。
因为我想要的效果是开始推流和结束推流都能通过代码来实现,所以就在网上找如何通过一个指令或者代码停止推流,但是找了很久都没有找到具体的方法(如果你们找到了或者有更简单的方法,还请不吝赐教)。以下是我解决问题的过程:
一、首先我在网上查找资料学习如何终止一个脚本,知道可以通过获取其进程的pid,然后用kill -9 pid
的方法杀死进程。于是我就想办法和获取sh脚本pid。方法如下:
首先在sh脚本中通过$$
获取脚本本身的pid,然后返回给python代码,供python获取,python获取脚本pid后,调用kill函数杀死对应进程。
shell脚本:
chmod 777 ./ffmpeg.sh #使脚本具有执行权限
echo $$
ffmpeg -thread_queue_size 512 -f video4linux2 -s 1280*720 -i "/dev/video0" -vcodec h264_omx -pix_fmt yuv420p -r 30 -s 1280*720 -g 60 -b:v 10M -bufsize 10M -an -f flv "rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_431165318_85852610&key=829133b26b0e1111898aac62df55dcf3&schedule=rtmp"
python代码:
import os
import signal
import time
p=os.popen("sh /home/pi/Desktop/python代码/ffmpeg/ffmpeg.sh")
pid=int(p.read()) #返回的pid是字符串,要进行强制类型转换
time.sleep(20)
os.kill(pid,signal.SIGKILL) #第二个参数表示强制杀死进程
但是运行代码之后还是停止不了推流,经检查后发现如果推流成功,存程序会卡在第四行,即调用sh脚本那一行代码。我试过在那一行代码后面进行一个输出,但是运行程序后并没有对应输出,就相当于程序阻塞在了那里,不断进行推流指令,后面的任何程序都无法执行。所以又进行了另一种方法。
二、把推流命令放在一个子进程或子线程中执行,在主进程或主线程中进行kill
命令,我选择的是在子线程中执行。
首先修改sh脚本,因为执行推流指令后无法执行后面代码,所以不能直接通过返回值获取pid,要把脚本pid保存在一个文件(/home/pi/Desktop/python代码/ffmpeg/ffmpeg.pid)中,然后主函数就从文件中获取pid。
sh脚本:
chmod 777 ./ffmpeg.sh #使脚本具有执行权限
echo $$ > /home/pi/Desktop/python代码/ffmpeg/ffmpeg.pid
ffmpeg -thread_queue_size 512 -f video4linux2 -s 1280*720 -i "/dev/video0" -vcodec h264_omx -pix_fmt yuv420p -r 30 -s 1280*720 -g 60 -b:v 10M -bufsize 10M -an -f flv "rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_431165318_85852610&key=829133b26b0e1111898aac62df55dcf3&schedule=rtmp"
python代码:
import os
import sys
import time
import signal
import threading
pid=-3def doffmpeg():os.popen("sh /home/pi/Desktop/python代码/ffmpeg/ffmpeg.sh")if __name__=='__main__':thread=threading.Thread(target=doffmpeg)thread.start() #开启一个新线程,和开启进程差不多#process=Process(target=doffmpeg)#process.start()time.sleep(20)f=open('/home/pi/Desktop/python代码/ffmpeg/ffmpeg.pid') #从文件中读取pidpid=int(f.read()) #因为读取出来的是字符串,所以要进行强制类型转换print("child_pid=", pid)os.kill(pid,signal.SIGKILL) #第二个参数表示强制杀死进程main_pid=os.getpid() #python程序pidprint("main_pid=", main_pid)
但是,运行程序并且执行了kill
指令后,仍然是无法停止摄像头推流,经和同学讨论后,觉得是pid不正确,推流指令可能是又开设了一个新的进程或线程来执行的。于是,我就在终端用ps -ef
或ps -aux
指令(ef或aux表示查看全部进程)查看全部进程,发现还真是这样:
由图中可以看出,我们获得的pid和脚本的pid是相同的,但是和推流指令的pid却不一样,并且推流指令的ppid是脚本的pid,说明脚本在执行推流指令时确实是新开了一个进程或者线程。那么如何获得推流指令的pid呢?
三、之后我学习了一些终端指令,发现可以通过进程名称来获取进程pid。
命令 ps
用标准语法查看系统上的每一个进程
ps -e
ps -ef
ps -eF
ps -ely
使用BSD语法查看系统上的每个进程
ps ax
ps axu
-a:显示所有进程(包括其他用户的进程)
-u:用户以及其他详细信息
-x:显示没有控制终端的进程
ps 命令参数介绍
-e: Select all processes. Identical to -A.
-a:显示所有进程(包括其他用户的进程)
-u:用户以及其他详细信息
-x:显示没有控制终端的进程
如何按名称或PID查找一个进程
#名称
ps -ef|grep tomcat
#PID
ps -ef|grep 17850
最简单的方法是使用 pgrep:
pgrep -f name
如果需要查找到 pid 之后 kill 掉该进程,还可以使用 pkill:
pkill -f name
经和同学讨论,我们觉得通过进程名称获取pid是匹配进程名称的关键字的,如下图:
因为我试着直接用推流指令当作名称匹配时出错了,所以我们只好在以下推流指令中找出独一无二、在其他进程或指令中没有的字符串,应该就能准确匹配到我们想要的指令的pid
ffmpeg -thread_queue_size 512 -f video4linux2 -s 1280720 -i “/dev/video0” -vcodec h264_omx -pix_fmt yuv420p -r 30 -s 1280720 -g 60 -b:v 10M -bufsize 10M -an -f flv “rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_431165318_85852610&key=829133b26b0e1111898aac62df55dcf3&schedule=rtmp”
这里我选取的字符串是/dev/video0
,如下图:
发现成功获取推流指令pid。因此,我们可以直接用指令:
pkill -f /dev/video0
通过匹配进程名称的方法kill
掉推流进程,而无需再获取pid了。
把上述指令写进另一个shell脚本,想要kill掉推流指令就调用此脚本即可。
shell脚本:
chmod 777 ./stopffmpeg.sh
pkill -f /dev/video0
echo "stop ffmpeg"
python代码:
import os
import sys
import time
import signal
import threading
from multiprocessing import Processdef doffmpeg(pid):os.popen("sh /home/pi/Desktop/python代码/ffmpeg/ffmpeg.sh")if __name__=='__main__':thread=threading.Thread(target=doffmpeg,args=(pid,))thread.start()time.sleep(20)os.popen("sh /home/pi/Desktop/python代码/ffmpeg/stopffmpeg.sh")
最后实现的功能勉强达到了,我感觉我的方法不太正规,但也找不到更好地方法了,如果有谁又更好的方法,欢迎留言,谢谢!
使用树莓派基于FFmpeg推流视频和摄像头到B站直播间相关推荐
- 基于ffmpeg+SDL 实时播放摄像头视频
基于ffmpeg+SDL 实时播放摄像头视频 基本流程 udp接收rtp数据流接收一帧数据后,转换为NAL单元送去解码 (这里特别说明一下,我本次用的接口是支持从连续数据流中自动分割出一个个NAL的, ...
- 嵌入式Linux下基于FFmpeg的视频硬件编解码
嵌入式Linux下基于FFmpeg的视频硬件编解码[图] http://www.c114.net ( 2012/3/1 15:41 ) 摘要: 对FFmpeg多媒体解决方案中的视频编解码流程进行研究. ...
- 基于 FFMPEG 的视频编码 源码(libavcodec,C++ Qt)
基于 FFMPEG 的视频编码 源码(libavcodec,C++ Qt) 昨晚把源代码好好整理了一下,加入了视频时间限制功能.源码放这里,大家随便用. 关于代码的解释可以看我另一篇博客: 基于 FF ...
- 基于 FFMPEG 的视频编码(libavcodec ,致敬雷霄骅)
基于 FFMPEG 的视频编码(libavcodec ,致敬雷霄骅) 本文参考了雷博士的博客: 最简单的基于FFmpeg的视频编码器-更新版(YUV编码为HEVC(H.265)) 还参考了另一篇博客: ...
- Qt基于FFmpeg实现视频转码
一.简述转码 转码的作用:封装格式的实现.(h264->mov.mp4.flv.avi(封装格式)等) 之前博客中提到如何把像素数据编码得到 H264 的压缩码流数据,但是一般的播放工具是没法直 ...
- 基于ffmpeg的视频处理与MPEG的压缩试验(下载安装使用全流程)
基于ffmpeg的视频处理与MPEG的压缩试验 ffmpeg介绍与基础知识 对提取到的图像进行处理 RGB并转化为YUV 对YUV进行DCT变换 对每个8*8的图像块进行进行量化操作 ffmpeg介绍 ...
- 不用obs不用直播姬,直接ffmpeg命令行推流RTSP到B站直播间
最近在做公司的直播准备工作,在尝试过程中,发现公司的"海康威视 DS-2CD1021FD-IW1"摄像头输出的是RTSP格式的. 经过各种搜索,尝试了用B站官方直播姬抓VLC窗口, ...
- 用ffmpeg在Windows11下的命令行模式推流到B站直播间
0. 通过修改环境变量,实现ffmpeg命令在任意命令行路径可用的方法.不用再使用下面的第1步了!! 注意:一路"确定 " 保存设置后,最好重启一下,这样就可以将ffmpeg变成系 ...
- 互联网晚报 | 1月25日 星期二 | 知乎首次举办上星晚会;微信视频号上线首个付费直播间;淘宝天猫“春节不打烊”活动正式上线...
今日看点 ✦ 淘宝天猫"春节不打烊"活动正式上线,20万商家春节照常发货 ✦ 微信视频号上线首个付费直播间,免费观看3分钟后需付费 ✦ 知乎首次举办上星晚会,2022知乎答案奇遇夜 ...
最新文章
- centos6.5 rsync+inotify同步配置笔记
- worpress安装mysql连不上_wordpress安装时连接不上MySQL8.0(已解决)Windows
- 九十五、轻松搞定Python中的Excel办公自动化系列
- php 数据库 加载图片,图片显示不出来,但是数据库里有显示
- Linux!为何他一人就写出这么强的系统?
- 使用mintty(_如何使用Mintty改善Cygwin控制台
- 2135亿!2018 双11阿里数据库技术战报新鲜出炉
- java中的 =运算符_(二十七)、java中的运算符
- Java 使用SAX解析XML文档
- java静态常量存在哪里,Java面试题及解析
- 热启动计算机的快捷键,电脑快捷键的用法
- 分享一个原始传奇的辅助脚本
- 清除Tomcat日志
- 查询硬盘序列号(serialNumber),系统安装日期等
- 数据告诉你,谁是2019年最硬核公链?
- 一座5g基站造价多少?
- services.msc 无法启动服务,原因可能是已被禁用或与其相关联的设备没有启动
- 农村信用社计算机基础知识,农村信用社计算机基础知识题五
- 喜马拉雅全站音频爬取
- 曾经连过的WiFi密码查询