播放rtsp视频流:

ffplay -vcodec h264_qsv -i rtsp://192.168.236.2/ch01.h264

低延迟播放rtsp

ffplay -fflags nobuffer -i rtsp://192.168.236.2/ch01.h264

更多选项

ffplay -analyzeduration 1 -fflags -nobuffer -probesize 32 -sync ext -i rtmp://localhost/live/STREAM_NAME

查看编/解码:

ffplay -codecs |grep h264

发现一个可以直接使用ffmpeg播放的方法,其实也是要求有sdl的库了.

ffmpeg -i rtsp://192.168.236.2/ch01.h264 -f sdl -

可以通过命令查看是否支持显示.

ffmpeg -formats |grep sdl 

ffplay 播放窗口大小

ffplay -x 800 -y 600 -i fwrj-1.mp4

ffplay 播放窗口位置

//从30s开始播放10s,播放完退出

ffplay -ss 00:00:30 -t 10 -autoexit video.mp4

//指定播放窗口大小为320x180

ffplay -x 320 -y 180 video.mp4

//音频波形可视化

ffplay -showmode 1 audio.aac

ffplay播放usb摄像头

ffplay -noborder -f v4l2 -input_format mjpeg -video_size 1920x1080 -i /dev/video9
ffplay -noborder -f v4l2 -input_format yuyv422 -video_size 1280x720 -i /dev/video9

经测试SPCA2650 AV Camera摄像头,在yuyv422模式下,只支持到720p,1080p不能播放,在mjpeg模式下支持得要高一些.可以支持到4k分辨率(3840x2160).
使用ffmpeg可以查看到输入数据源的fps,其中yuyv422的720p模式下,输入只有10fps.mjpeg模式下号称可以达到30fps,实测只有14fps.

ffmpeg -input_format mjpeg -video_size 1280x720 -i /dev/video9 -pix_fmt yuv420p  -f sdl -
ffmpeg -input_format yuyv422 -video_size 1280x720 -i /dev/video9 -pix_fmt yuv420p -f sdl -

测试发现,就1080p的时候,能够达到最快的速度.

ffmpeg -input_format mjpeg -video_size 1920x1080 -i /dev/video9 -f null -

ffplay可选参数
参数 说明

-x width    强制以 “width” 宽度显示
-y height    强制以 “height” 高度显示
-an    禁止音频
-vn    禁止视频
-ss pos    跳转到指定的位置(秒)
-t duration    播放 “duration” 秒音/视频
-bytes    按字节跳转
-nodisp    禁止图像显示(只输出音频)
-f fmt    强制使用 “fmt” 格式
-window_title title    设置窗口标题(默认为输入文件名)
-loop number    循环播放 “number” 次(0将一直循环)
-showmode mode    设置显示模式,可选mode: 0, 显示视频; 1, 显示音频波形; 2, 显示音频频带。默认为0, 播放时按w键可切换mode
-i input_file    指定输入文件
-sync type    设置主时钟为音频、视频、或者外部。默认为音频。主时钟用来进行音视频同步
-threads count    设置线程个数
-autoexit    播放完成后自动退出
-exitonkeydown    任意键按下时退出
-exitonmousedown    任意鼠标按键按下时退出
-acodec codec_name    强制指定音频解码器为 “codec_name”
-vcodec codec_name    强制指定视频解码器为 “codec_name”
-scodec codec_name    强制指定字幕解码器为 “codec_name”

<html><head>
   <script type="text/javascript">
      function setvalue(){   
         var framewidth=prompt("Enter the default right column width : ", "50")

         var width = parseInt(framewidth);
         width = isNaN(width) ? 50 : width;

         var val = (100 - width) + "%, " + width + "%";

         document.getElementById("set").cols = val
      }

      window.onload = setvalue;
   </script>
</head>
        <frameset cols="*,1%" frameborder="NO" framespacing="0" border="0" id="set">
            <frame src="https://const.net.cn" name="left" scrolling="no"/>
            <frame src="https://const.net.cn" name="right" scrolling="no"/>
        <frameset>
</html>

这个代码是文心一言生成的,验证不了,思路清奇,gstreamer.sourceforge.net/gst已经无法访问,go引入的其他库有时候就是有这样的风险.

package main  
  
import (  
 "fmt"  
 "os"  
  
 "gstreamer.sourceforge.net/gst"  
)  
  
func main() {  
 // 初始化 GStreamer  
 gst.Init(nil)  
  
 // 创建播放器元素  
 player := gst.NewPlayer("videoconvert")  
  
 // 设置视频文件路径  
 uri := "file:///path/to/video.mp4"  
 player.SetProperty("uri", uri)  
  
 // 创建窗口元素  
 window := gst.NewWindow("GStreamer Player")  
 window.SetProperty("title", "GStreamer Player")  
 window.Connect("delete-event", func() bool {  
 // 关闭播放器  
 player.Stop()  
 // 退出应用程序  
 os.Exit(0)  
 return false  
 })  
 window.Show()  
  
 // 创建渲染器元素  
 renderer := gst.NewRenderer("autovideosink")  
 renderer.SetProperty("force-aspect-ratio", true)  
 renderer.SetProperty("x", 0)  
 renderer.SetProperty("y", 0)  
 renderer.Connect("sink-message", func(element *gst.Element, message *gst.Message) {  
 switch message.Type() {  
 case gst.MessageError:  
 fmt.Println("Error:", message.Error())  
 case gst.MessageEOS:  
 fmt.Println("End of stream")  
 default:  
 fmt.Println("Other message:", message)  
 }  
 })  
 renderer.SetWindow(window)  
 player.Link(renderer)  
 player.Play()  
}

这段代码使用了 GStreamer 库来播放视频文件。下面我来讲解一下实现逻辑:

导入所需的包:我们导入了 gst 包,这是 GStreamer 在 Go 语言中的实现。此外,我们还导入了 os 包来处理退出操作。
初始化 GStreamer:通过调用 gst.Init(nil) 来初始化 GStreamer 库。
创建播放器元素:使用 gst.NewPlayer("videoconvert") 创建一个播放器元素,该元素用于播放视频文件。这里的参数 "videoconvert" 表示在播放之前转换视频格式。
设置视频文件路径:通过调用 player.SetProperty("uri", uri) 设置要播放的视频文件的路径。在这里,我们使用 uri 变量来存储文件路径。你可以将 uri 替换为你自己的视频文件路径。
创建窗口元素:使用 gst.NewWindow("GStreamer Player") 创建一个窗口元素,该元素用于显示视频。我们设置了窗口的标题属性为 "GStreamer Player"。通过调用 window.Connect() 方法连接到窗口的删除事件,当用户关闭窗口时,会执行相应的操作。
创建渲染器元素:使用 gst.NewRenderer("autovideosink") 创建一个渲染器元素,该元素用于将视频渲染到窗口中。我们设置了渲染器的属性,如强制保持宽高比、窗口的位置等。通过调用 renderer.Connect() 方法连接到渲染器的消息事件,以处理错误、结束流等消息。在这里,我们使用匿名函数作为回调函数来处理消息事件。在回调函数中,我们根据消息类型打印相应的信息。

结论
通过对MediaStream的控制,即设置MediaStreamTrack.enabled来实现静音开关效果的切换。

MediaStreamTrack表示流中的单个媒体轨道。通常,这些是音频或视频轨道,但也可以存在其他轨道类型。
MediaStreamTrack.enabled如果为true,则enabled表示允许轨道将其实际媒体呈现到输出。当enabled设置为时false,轨道仅生成空白帧。空的音频帧将每个样本的值设置为0。空的视频帧将每个像素的值设置为黑色。

官方介绍地址:
https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack/enabled

MediaStreamTrack接口上的enabled属性是一个布尔值,如果允许轨迹渲染源流,则为true;如果不允许,则为false。这可用于有意使音轨静音。

启用时,轨道的数据从源输出到目的地;否则,输出空帧。

在音频的情况下,禁用的音轨会生成静默帧(即每个采样值为0的帧)。对于视频轨迹,每一帧都完全用黑色像素填充。

从本质上讲,enabled的值表示典型用户对音轨的静音状态的看法,而静音属性表示音轨暂时无法输出数据的状态,例如帧在传输中丢失的情况。

MediaStream.getTracks()返回流中所有的MediaStreamTrack列表。
遍历流中的每个音频轨道,然后设置enabled为true或false,来控制麦克风静音或者取消静音。

var tracks = stream.getTracks();  
tracks.forEach(item => {
    if (item.kind === 'audio') {
        item.enabled = status;
    }
});

WebRTC turn服务器搭建
不使用数据库直接设置密码,同时支持turn和stun二个协议,可以使用TrickleICE工具测试.
https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/

git clone https://github.com/coturn/coturn.git
cd coturn
./configure --prefix=/usr/local/coturn
sudo make -j && make install
cd /usr/local/coturn/bin
./turnserver -a --no-tls --no-dtls -u testuser:testpwd -r myrealm -v
./turnutils_peer -v
./turnutils_uclient -u testuser -w testpwd -e 192.168.0.100 -r 3480 192.168.0.100

搭建coturn stun/turn 服务器

./turnserver -a --no-tls -u testuser:testpwd -r myrealm -v --min-port 60000 --max-port 62000 --external-ip xxx.xxx.xxx.xxx -o --no-stun --no-tcp --no-tls

https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ 测试的时候,会提示701错误,实际测试不影响使用的.

另外,在公网上测试webrtc的时候,需要注意的一个问题是, 在answer端,需要先准备后视频和rtcpeer,不要等到offer sdp过来的时候再去打开视频,有可能会导致连不上.也是无意中发现这个问题的.

在手机端的时候,一定要在video元素里面加上autoplay,不然不会自动播放的,还以为没有连接成功.