腾讯实时音视频 C# 的 Demo 解读(一)
开篇
因为公司项目需要,研究了下腾讯的实时音视频的C# Winform版本的Demo。
当然其他平台也有,不是我主要负责。
经过2天的摸索,对其代码和原理进行了一个简单的梳理。因为才接触腾讯的音视频直播,同时C# Winform相关的知识已经5年没碰了。
所以下面的内容,应该会出现一些偏差,仅供大家参考。
腾讯的Demo 下载地址:
核心类解读
其实整个项目的最为核心的文件是:TXLiteAVVideoViews。翻译过来的意思应该是腾讯轻量级的音视频视图。
在这个文件中,包含了3个非常重要的类,我认为音视频在C#`层面上的核心。
- TXLiteAVVideoView,继承自Pannel,将视频帧渲染到空间上。
- TXLiteAVVideoViewManager,继承自ITRTCVideoRenderCallBack,承上启下,将底层传递的帧数据再传递给TXLiteAVVideoView
- FrameBufferInfo帧数据的封装实体。
TXLiteAVVideoView
以下为我把非核心代码删除后的简单模型。
public class TXLiteAVVideoView: Panel {
// 帧缓存,可以理解为视频暂停时候的一个画面
private volatile FrameBufferInfo _mArgbFrame = new FrameBufferInfo();
public bool AppendVideoFrame(byte[] data, int width, int height, TRTCVideoPixelFormat videoFormat, TRTCVideoRotation rotation) {
//...
}
protected override void OnPaint(PaintEventArgs pe) {
//....
}
}
- 该类继承了Pannl,又重写了OnPaint,所以可以猜测目的是为了根据Frame数据来绘图。
- _mArgbFrame 的作用是保存的某一时刻的一帧数据,保存起来的目的是为了方便OnPaint来绘图,它由什么地方传递过来的了,我们看下面这段话?
- AppendVideoFrame由TXLiteAVVideoViewManager来调用,其中就传入了byte[] data这个还没有处理的帧的数据。
所以由此我们可以简单分析总结下:该类通过方法AppendVideoFrame接收TXLiteAVVideoViewManager传递过来的帧数据,在将帧数据保存到局部变量_mArgbFrame后调用refresh方法,该方法会调用重写后的OnPaint来画图。
TXLiteAVVideoViewManager
同样简化下代码:
class TXLiteAVVideoViewManager: ITRTCVideoRenderCallback {
private volatile Dictionary<string,TXLiteAVVideoView> _mMapViews;
public void onRenderVideoFrame(string userId, TRTCVideoStreamType streamType, TRTCVideoFrame frame) {
//...
}
}
- 该类实现了接口ITRTCVideoRenderCallback的方法onRenderVideoFrame。通过签名,我大胆的猜测了从服务器拉数据的时候,数据中应该有远程用户的id,以及对应的数据帧和类型。
- 其底层可能在不停的拉数据,然后不停的调用这个实现类来传递给对应的TXLiteAVVideoView进行视图渲染。
- _mMapViews这个局部变量,通过userId-streamType来作为key,其TXLiteAVVideView作为value来保存的数据。
我们可以简单看看onRenderVideoFrame的实现
public void onRenderVideoFrame(string userId, TRTCVideoStreamType streamType, TRTCVideoFrame frame) {
//....
TXLiteAVVideoView view = null;
lock(_mMapViews) {
view = _mMapViews[GetKey(userId, streamType)];
}
//调用 AppendVideoFrame 进行帧的渲染
view?.AppendVideoFrame(frame.data, (int) frame.width, (int) frame.height, frame.videoFormat, frame.rotation);
}
其本质也是从Dictionary中通过GetKey(userId, streamType)来构成key,获取到对应的view,然后进行AppendVideoFrame.
FrameBufferInfo
这个类的实现如下:
class FrameBufferInfo
{
public byte[] data { get; set; }
public int width { get; set; }
public int height { get; set; }
public bool newFrame { get; set; }
/**
* Rotation 是是否旋转
*/
public TRTCVideoRotation rotation { get; set; }
}
表示的应该是这个帧如何处理。
结语
这是腾讯音视频实时通信的第一篇分析,后面会根据情况,看看有没有更多有意义的可以写文。
希望对大家有帮助。
如果本文对你有帮助,欢迎评论、点赞、转发、收藏、关注!