# 视频管理
# 视频数据采集管理
# 设置要开启的摄像头类型
视频采集前,可以指定要开启的摄像头
首先,获取摄像头列表
/// <summary>
/// 摄像头列表
/// </summary>
public List<JCMediaDeviceCamera> cameras
其中,JCMediaDeviceCamera 有以下几个变量
/// <summary>
/// 名称
/// </summary>
public string cameraName { get; internal set; }
/// <summary>
/// id
/// </summary>
public string cameraId
切换摄像头
/// <summary>
/// 切换摄像头
/// </summary>
/// <param name="camera">要切换的摄像头</param>
/// <returns>true为切换成功,false为切换失败</returns>
public bool switchCamera(JCMediaDeviceCamera camera)
示例代码
// 获取摄像头列表
List<JCMediaDeviceCamera> cameraDevices = mediaDevice.cameraDevices;
// 切换摄像头
mediaDevice.switchCamera(mediaDevice.cameras[0]);
# 设置摄像头采集分辨率
您可以通过自定义摄像头采集参数实现不同的视频分辨率,如采集的高度、宽度和帧速率。
摄像头采集属性设置接口如下:
/// <summary>
/// 设定摄像头分辨率,请在调用startCamera()接口之前调用才会生效
/// </summary>
/// <param name="width">摄像头分辨率宽</param>
/// <param name="height">摄像头分辨率高</param>
/// <param name="framerate">帧速率</param>
public void setCameraProperty(int width, int height, int framerate)
示例代码
// 设置摄像头采集属性
mediaDevice.setCameraProperty(640, 360, 30);
# 自定义视频输入源
在视频通话中,您可以自定义视频输入源,菊风提供将视频文件作为视频源的方案以实现该功能:
- 调用 startVideoFile (opens new window) 开启该功能。(调用 stopVideoFile (opens new window) 关闭该功能)
- 调用 setVideoFileFrame (opens new window) 逐帧添加视频数据。
- 进行 视频画面渲染。
// 开启以视频文件作为视频源的功能
mediaDevice.startVideoFile();
// 添加视频数据源
mediaDevice.setVideoFileFrame(data,JCMediaDevice.I420, "width","height","angle","mirror", "keyFrame");
// 渲染画面
...
TIP
startVideoFile() 函数会自动关闭摄像头。
参数介绍
参数 | 描述 |
---|---|
data | 画面二进制数据 |
format | 视频像素格式。当 format 为 H264 (opens new window) 格式并且是关键帧,则需要将 0x67 0x68 0x41 的数据作为一帧传入,并且关键帧要以固定间隔传入,例如5秒,否则一开始可能有几秒对端无法显示视频。 |
width | 宽 |
height | 高 |
angle | 视频旋转角度,90 的倍数 |
mirror | 0 不镜像,1进行左右镜像 |
keyFrame | 是否为关键帧,针对 format 为 H264 (opens new window) - true 是关键帧 - false 不是关键帧 |
# 视频渲染管理
# 创建本地和远端视频画面
- 本地视频渲染
本地视频渲染通过调用 startCameraVideo 接口获得本地视频对象用于 UI 界面显示,该接口会打开摄像头
/// <summary>
/// 获取预览视频对象,通过此对象能获得视图用于UI显示
/// </summary>
/// <param name="mode">渲染方式</param>
/// <returns>JCMediaDeviceVideoCanvas对象</returns>
public JCMediaDeviceVideoCanvas startCameraVideo(JCMediaDeviceRenderMode mode)
其中,渲染模式(JCMediaDeviceRenderMode)有以下三种
名称 | 描述 |
---|---|
FULLSCREEN | 铺满窗口 |
FULLCONTENT | 全图像显示,会有黑边,但在窗口跟图像比例相同的情况下不会有黑边 |
AUTO | 自适应 |
- 远端视频渲染
您可以调用 startVideo 方法获取对端视频对象并进行渲染
/// <summary>
/// 获得视频对象,通过此对象能获得视图用于UI显示
/// </summary>
/// <param name="videoSource">渲染标识串,比如 JCMediaChannelParticipant JCCallItem 中的 renderId,当videoSource 为 videoFileId 时,内部会调用 startVideoFile</param>
/// <param name="mode">渲染模式</param>
/// <returns>JCMediaDeviceVideoCanvas对象</returns>
public JCMediaDeviceVideoCanvas startVideo(string videoSource, JCMediaDeviceRenderMode mode)
示例代码
// 获取摄像头列表
List<JCMediaDeviceCamera> cameraDevices = mediaDevice.cameras;
// 打开本地视频预览
JCMediaDeviceVideoCanvas localCanvas = mediaDevice.startCameraVideo(JCMediaDeviceRenderMode.FULLCONTENT);
ImageBrush image = new ImageBrush(localCanvas.videoView);
image.Stretch = Stretch.Uniform;
this.label.Background = image;
// 远端视频渲染,renderId来源于通话对象,一对一为JCCallItem对象,多方为JCMediaChannelParticipant对象
JCMediaDeviceVideoCanvas remoteCanvas = mediaDevice.startVideo(renderId, JCMediaDeviceRenderMode.FULLSCREEN);
ImageBrush image = new ImageBrush(remoteCanvas.videoView);
image.Stretch = Stretch.Uniform;
this.label.Background = image;
# 销毁本地和远端视频画面
在视频通话结束或者视频通话中,如果想销毁视频画面,可以调用下面的接口
/// <summary>
/// 停止视频
/// </summary>
/// <param name="canvas">JCMediaDeviceVideoCanvas对象,由startVideo获得</param>
public void stopVideo(JCMediaDeviceVideoCanvas canvas)
示例代码
JCMediaDeviceVideoCanvas localCanvas = mediaDevice.startCameraVideo(JCMediaDeviceRenderMode.FULLCONTENT);
JCMediaDeviceVideoCanvas remoteCanvas = mediaDevice.startVideo(renderId, JCMediaDeviceRenderMode.FULLSCREEN);
if (localCanvas != null)
{
this.smvideoGrid.Background = null;
mediaDevice.stopVideo(localCanvas);
localCanvas = null;
}
if (remoteCanvas != null)
{
this.fullvideoGrid.Background = null;
mediaDevice.stopVideo(remoteCanvas);
remoteCanvas = null;
}
# 视频通话截图
/// <summary>
/// 视频通话截图
/// </summary>
/// <param name="width">截屏宽度像素,-1为视频源像素</param>
/// <param name="height">截屏高度像素,-1为视频源像素</param>
/// <param name="filePath">文件路径</param>
/// <returns>是否成功</returns>
public bool snapshot(int width, int height, string filePath)
# 更新视频渲染标识
如果想替换当前摄像头视频画面,可以调用下面的接口
/// <summary>
/// 更新视频渲染标识
/// </summary>
/// <param name="videoSource">渲染标识</param>
/// <returns>成功失败</returns>
public bool replace(string videoSource)
# 暂停渲染
如果想暂停画面的渲染可以调用如下接口
/// <summary>
/// 暂停渲染
/// </summary>
/// <returns>成功失败</returns>
public bool pause()
# 恢复渲染
如果想对已暂停的画面继续进行渲染,可以调用下面的接口
/// <summary>
/// 恢复渲染
/// </summary>
/// <returns>成功失败</returns>
public bool resume()
# 解决视频渲染黑屏问题
如果在集成过程中遇到视频黑屏的问题,您可以通过软件渲染的方式解决。通过以下几个步骤实现软件渲染:
- 调用 JCMediaDevice 对象中的 startCamera 开启自身摄像头。
- 创建 ZmfBitmap 对象,打开自身的视频渲染。
- 调用 JCMediaChannel 对象中的 requestVideo 请求其他成员的视频流。(参数中设置开启)
- 创建 ZmfBitmap 对象,打开其他成员的视频渲染。
在您不需要软件渲染的时候,通过以下几个步骤关闭软件渲染:
- 当不需要渲染时,调用 ZmfBitmap 对象的 Dispose 方法停止渲染,并置空 ZmfBitmap 对象。
- 调用 JCMediaDevice 对象中 stopCamera 关闭自身摄像头。
- 调用 JCMediaChannel 对象中的 requestVideo 关闭其他成员的视频流。(参数中设置关闭)
开启软件渲染示例代码
// 1. 打开自身摄像头
mediaDevice.startCamera();
// 2. 创建 ZmfBitmap 对象,打开自身的视频渲染
ZmfBitmap _callLocalZmfBitmap = new ZmfBitmap(mediaDevice.camera.cameraId,
(string renderId, ImageSource source, int width, int height, int angle) =>
{
if (source != null)
{
// 通过 source 构建 ImageBrush 对象设置画面
ImageBrush brush = new ImageBrush(source);
brush.Stretch = Stretch.UniformToFill;
viewCallLocalVideo.Background = brush;
// 开启自身视频渲染,可以选择开启镜像,同时设置视频画面的初始方向
TransformGroup group = new TransformGroup();
ScaleTransform scaleTransform = new ScaleTransform();
scaleTransform.ScaleX = -1;
group.Children.Add(scaleTransform);
group.Children.Add(new RotateTransform(angle));
viewCallLocalVideo.LayoutTransform = group;
}
}, (string renderId, ImageSource source, int width, int height, int angle) =>{
// windows 下开启自身视频渲染不会收到此回调
});
// 3. 请求其他成员的视频流
mediaChannel.requestScreenVideo(mediaChannel.screenRenderId, (JCMediaChannelPictureSize)Properties.Settings.Default.ConfPictureSize);
// 4. 创建 ZmfBitmap 对象,打开其他成员的视频渲染
ZmfBitmap _confOtherZmfBitmap_others = new ZmfBitmap(jCMediaChannelParticipant.renderId,
(string renderId, ImageSource source, int width, int height, int angle) =>
{
if (source != null)
{
// 通过 source 构建 ImageBrush 对象设置画面
ImageBrush brush = new ImageBrush(source);
brush.Stretch = getStretchByRenderMode();
viewConfOtherVideo.Background = brush;
viewConfOtherVideo.LayoutTransform = new RotateTransform(angle);
}
}, (string renderId, ImageSource source, int width, int height, int angle) =>
{
// 处理视频旋转
viewConfOtherVideo.LayoutTransform = new RotateTransform(angle);
});
关闭软件渲染的示例代码
// 1. 调用 ZmfBitmap 对象的 Dispose 方法停止渲染,并置空 ZmfBitmap 对象。
_callLocalZmfBitmap.Dispose();
_callLocalZmfBitmap = null;
_confOtherZmfBitmap_others.Dispose();
_confOtherZmfBitmap_others = null;
// 2. 关闭自身摄像头
mediaDevice.stopCamera();
// 3. 关闭其他成员的视频流
mediaChannel.requestVideo(jCMediaChannelParticipant, JCMediaChannelPictureSize.None);
相关 API 介绍
// 构造方法。renderId 为摄像头id或者视频流,ResizeHandler 为视频渲染大小变化的接口回调,rotate 为视频渲染角度变化的接口回调
public ZmfBitmap(string renderId, ResizeHandler resize, RotateHandler rotate);
// 停止渲染
public void Dispose();
// 视频渲染大小变化的接口回调
public delegate void ResizeHandler(string renderId, ImageSource srouce, int width, int height, int angle);
// 视频渲染角度变化的接口回调
public delegate void RotateHandler(string renderId, ImageSource srouce, int width, int height, int angle);
# 视频设备管理
视频设备管理主要用到 JCMediaDevice 类中的方法,具体如下:
# 获取当前使用摄像头和默认摄像头
/// <summary>
/// 当前使用摄像头
/// </summary>
public JCMediaDeviceCamera camera
/// <summary>
/// 默认摄像头
/// </summary>
public JCMediaDeviceCamera defaultCamera
# 开启关闭摄像头
/// <summary>
/// 开启摄像头
/// </summary>
/// <returns>true为开启成功,false为开启失败</returns>
public bool startCamera()
/// <summary>
/// 关闭摄像头
/// </summary>
/// <returns>true为关闭成功,false为关闭失败</returns>
public bool stopCamera()
# 切换摄像头
/// <summary>
/// 切换摄像头
/// </summary>
/// <param name="camera">要切换的摄像头</param>
/// <returns>true为切换成功,false为切换失败</returns>
public bool switchCamera(JCMediaDeviceCamera camera)
示例代码
// 打开摄像头
mediaDevice.startCamera();
// 关闭摄像头
mediaDevice.stopCamera();
// 切换摄像头
mediaDevice.switchCamera(mediaDevice.cameras[0]);