腾讯实时音视频 C# 的 Demo 解读(一)

腾讯实时音视频 C# 的 Demo 解读(一)

编码文章call10242025-10-13 17:03:302A+A-



开篇

因为公司项目需要,研究了下腾讯的实时音视频的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; }
}

表示的应该是这个帧如何处理。

结语

这是腾讯音视频实时通信的第一篇分析,后面会根据情况,看看有没有更多有意义的可以写文。

希望对大家有帮助。


如果本文对你有帮助,欢迎评论、点赞、转发、收藏、关注!

点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4