Use Raspberry Pi to push streaming video and camera to station B live room based on FFmpeg


Prerequisite
1. First, you must have a Raspberry Pi, connected to the camera, and be able to access the Internet.
2. Passed the real-name authentication in Bilibili, and opened the live broadcast room. (Very simple, after passing the real-name authentication, it can be activated directly).
3. FFmpeg. Push streaming uses FFmpeg by default, and FFmpeg is installed by default in the official Raspberry Pi system. You can use ffpmeg -version to view detailed information.

Obtain the rtmp address and live code from the live broadcast room of station B

After applying for the live broadcast room of station B, use a computer to start the live broadcast. You must use a computer to get the rtmp address and live broadcast code. You can't get the rtmp address and live broadcast code when you use your mobile phone to live broadcast Ji Kai broadcast.
After you click to start the live broadcast, the rtmp address and live broadcast code (as shown in the figure below) will appear, and the rtmp address and live broadcast code are spliced ​​together to be the address of the ffpmeg push stream later.
Insert picture description here

Use ffpmeg to push video or camera in the terminal

The following are the streaming commands in the Raspbian system:


#Push Stream USB camera (including audio, audio source is audio file) ffmpeg -thread_queue_size 512 -f video4linux2 -s 1280 720 -i "video source" -stream_loop -1 -i "audio source" -vcodec h264_omx -pix_fmt yuv420p -r 30 -s 1280 720 -g 60 -b:v 10M -bufsize 10M -acodec aac -ac 2 -ar 44100 -ab 128k -f flv "Push Stream Address"


#Push Stream USB camera (including audio, audio source microphone) ffmpeg -thread_queue_size 512 -f video4linux2 -s 1280 720 -i "video source" -i "audio source" -vcodec h264_omx -pix_fmt yuv420p -r 30 -s 1280 720- g 60 -b:v 10M -bufsize 10M -acodec aac -ac 2 -ar 44100 -ab 128k -f flv "Push Stream Address"


#Push Stream USB camera (not including audio) ffmpeg -thread_queue_size 512 -f video4linux2 -s 1280 720 -i "video source" -vcodec h264_omx -pix_fmt yuv420p -r 30 -s 1280 720 -g 60 -b:v 10M -bufsize 10M -an -f flv "Push Streaming Address"

#推流
视频ffmpeg -re -i "Video Source" -vcodec copy -acodec aac -b:a 192k -f flv "Push Stream Address"

Example of Raspberry Pi camera streaming:

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”

Among them, /dev/video0 is the Raspberry Pi camera device node, which is used as the input source for streaming. The string after flv is the rtmp address of the live broadcast room of station B plus the live broadcast code.
Raspberry Pi video streaming example

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”

The following is the push stream command in Windows system

#Push stream USB camera (including audio, audio source is audio file)
ffmpeg -f dshow -s 1280 720 -r 1024 -i video="video source" -stream_loop -1 -i "audio source" -vcodec libx264 -pix_fmt yuv420p -r 30 -s 1280 720 -g 60 -b:v 5000k -acodec aac -ac 2 -ar 44100 -ab 128k -preset:v ultrafast -tune:v zerolatency -f flv "Push Stream Address"

#Push Stream USB camera (including audio, audio source microphone)
ffmpeg -f dshow -s 1280 720 -r 1024 -i video="video source" -i "audio source" -vcodec libx264 -pix_fmt yuv420p -r 30 -s 1280 720 -g 60 -b:v 5000k -acodec aac -ac 2 -ar 44100 -ab 128k -preset:v ultrafast -tune:v zerolatency -f flv "Push Stream Address"

#Push Stream USB camera (not including audio)
ffmpeg -f dshow -s 1280 720 -r 1024 -i video="video source" -vcodec libx264 -pix_fmt yuv420p -r 30 -s 1280 720 -g 60 -b:v 5000k -an -preset:v ultrafast -tune:v zerolatency -f flv "Push Stream Address"

#推流
视频ffmpeg -re -i "Video Source" -vcodec copy -acodec aac -b:a 192k -f flv "Push Stream Address"

The above commands have not been carefully tested. Different environments require different parameters. Please learn the usage of FFmpeg by yourself.

Basic usage of FFmpeg:

ffmpeg [global option] {[input file option] -i input file}… {[output file option] output file}…

Brief introduction of parameters:

-f: input format (video4linux2)
-i: input source
-s: video resolution
-r: required frame rate
-vcodec: video codec
-vb: video bitrate
-bufsize: buffer size (for streaming It is important to say)
-vf: pixel format
-g: GOP (group of pictures, important for streaming)
-an: do not use audio
-f: output format

ffpmeg documentation

Use python to control Raspberry Pi push streaming

The above push streaming command is executed on the Raspberry Pi terminal, so how do I run the python program to push the camera?
We can use the python program to call the sh script to execute the push stream command. There are many ways for python to call shell scripts. You can check it on the Internet. I mainly tried two:
1. os.system("command") method.
This method will return a 0 if executed successfully.
2. os.popen("command") method
The return value of this method is a file object, and the return value can be obtained through the read() method. E.g:

f=popen("sh ./ffmpeg.sh")
print(f.read())

First, we create a new file and save it as ffmpeg.sh, then edit the following content and save it:

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 calls the shell script to execute the push streaming code as follows:

import os
os.popen("sh /home/pi/Desktop/python代码/ffmpeg/ffmpeg.sh")

How to stop streaming on Raspberry Pi

When trying to use python to call a shell script to push the camera, I found a problem, that is, I don’t know how to stop the camera.
Camera push is not like video push. The video push ends after the video is pushed, but the camera push will continue, even after the python code is stopped and closed, the script will still run in the background. In addition, put the B station The push streaming command is still running after the live broadcast room is closed. After closing the python program and the live broadcast room of station B, you can still see the camera screen when you open the live broadcast room of station B again. Unless the Raspberry Pi is restarted, the push instruction will always be executed.
Because the effect I want is that both the start and end of the push can be achieved through code, so I found out how to stop the push through an instruction or code on the Internet, but I did not find a specific method for a long time (if you find Or there is a simpler method, please feel free to enlighten me). The following is my process of solving the problem:
1. First, I found information on the Internet to learn how to terminate a script, knowing that I can get the pid of its process, and then use kill -9 pidthe method to kill the process. So I tried to find a way and get the pid of the sh script. The method is as follows:
First, $$obtain the pid of the script itself in the sh script , and then return it to the python code for python to obtain. After python obtains the script pid, call the kill function to kill the corresponding process.
shell script:

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 code:

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) #第二个参数表示强制杀死进程

But after running the code, I still can't stop the push. After checking, it is found that if the push is successful, the stored program will be stuck in the fourth line, that is, the line of code that calls the sh script. I tried to perform an output after that line of code, but there is no corresponding output after running the program, which is equivalent to the program being blocked there and continuously pushing instructions, and any subsequent programs cannot be executed. So another method was carried out.
2. Put the push command to be executed in a sub-process or sub-thread, and execute the killcommand in the main process or main thread . I chose to execute it in the sub-thread.
First modify the sh script, because the following code cannot be executed after the push instruction is executed, so the pid cannot be obtained directly from the return value, and the script pid must be saved in a file (/home/pi/Desktop/python code/ffmpeg/ffmpeg.pid) Then the main function gets the pid from the file.
sh script:

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 code:

import os
import sys
import time
import signal
import threading
pid=-3

def 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') #从文件中读取pid
    pid=int(f.read()) #因为读取出来的是字符串,所以要进行强制类型转换
    print("child_pid=", pid)
	os.kill(pid,signal.SIGKILL) #第二个参数表示强制杀死进程

    main_pid=os.getpid()  #python程序pid
    print("main_pid=", main_pid)

However, after running the program and executing the killinstructions, I still cannot stop the camera streaming. After discussing with my classmates, I feel that the pid is incorrect. The streaming instruction may be executed by a new process or thread. So, I used the ps -efor ps -auxcommand (ef or aux to view all processes) in the terminal to view all processes, and found that it was really like this:
Insert picture description here
As can be seen from the figure, the pid we obtained is the same as the pid of the script, but it is the same as the push stream. The pid of the instruction is different, and the ppid of the push instruction is the pid of the script, indicating that a new process or thread is indeed opened when the script executes the push instruction. So how to get the pid of the push instruction?
3. After learning some terminal commands, I found that the process pid can be obtained by the process name.
The command ps
uses standard syntax to view every process on the system

ps -e
ps -ef
ps -eF
ps -ely

Use BSD syntax to view every process on the system

ps ax
ps axu

-a: display all processes (including processes of other users)
-u: users and other detailed information
-x: display processes that do not control the terminal

ps command parameter introduction

-e: Select all processes. Identical to -A.
-a: display all processes (including processes of other users)
-u: users and other detailed information
-x: display processes that do not control the terminal

How to find a process by name or PID

# Name
PS -ef | grep Tomcat
# PID
PS -ef | grep 17850

The easiest way is to use pgrep:

pgrep -f name

If you need to kill the process after finding the pid, you can also use pkill:

pkill -f name

After discussing with classmates, we feel that getting the pid by the process name is a keyword that matches the process name, as shown in the figure below:
Insert picture description here
Because I tried to directly use the push instruction as a name match, an error occurred, so we had to use the following push instruction Find a string that is unique and not in other processes or instructions, and it should be able to accurately match the pid of the instruction we want

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”

The string I selected here is /dev/video0as shown in the figure below: It was
Insert picture description here
found that the push instruction pid was successfully obtained. Therefore, we can directly use the command:

pkill -f /dev/video0

By matching the process name, the killpush process is dropped, without the need to obtain the pid.
Write the above instructions into another shell script, and call this script if you want to kill the push instruction.
shell script:

chmod 777 ./stopffmpeg.sh
pkill -f /dev/video0
echo "stop ffmpeg"

python code:

import os
import sys
import time
import signal
import threading
from multiprocessing import Process

def 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")

The function achieved in the end is barely achieved. I feel that my method is not formal, but I can't find a better method. If anyone has a better method, please leave a message, thank you!

Guess you like

Origin blog.csdn.net/qq_50866711/article/details/113839586