直播前完成

This commit is contained in:
lxmou666 2020-12-28 17:22:22 +08:00
parent 7ab41709bf
commit f047cd3139
7 changed files with 229 additions and 37 deletions

View File

@ -242,10 +242,10 @@
</Style>
<!--默认ScrollBar-->
<Style TargetType="ScrollBar" BasedOn="{StaticResource for_scrollbar}"/>
<Style x:Key="CusScrollBar" TargetType="ScrollBar" BasedOn="{StaticResource for_scrollbar}"/>
<!--默认ScrollView-->
<Style TargetType="ScrollViewer" BasedOn="{StaticResource for_scrollviewer}"/>
<Style x:Key="CusScroll" TargetType="ScrollViewer" BasedOn="{StaticResource for_scrollviewer}"/>
<Style x:Key="LeftIndicatorStyle" TargetType="{x:Type Metro:SegmentControl}">
<Setter Property="Padding" Value="0" />

View File

@ -102,7 +102,7 @@ namespace JianGongYun.TRTC
callerWindow.Hide();//隐藏调用窗口
CurrentLiveWindow.Show();
}
private static SettingWindowViewModel settingWindowViewModel = SettingWindowViewModel.GetInstance();
@ -117,11 +117,72 @@ namespace JianGongYun.TRTC
/// <param name="parent">视频容器</param>
public static void StartVideoMain(Panel parent)
{
lTRTCCloud.startLocalPreview(IntPtr.Zero);
var liveWinMode = CurrentLiveWindow.DataContext as LiveWindowViewModel;
liveWinMode.CameraRunning = true;
AddCustomVideoView(parent, CurrentClassroomEntity.TeacherId, TRTCVideoStreamType.TRTCVideoStreamTypeBig, true);
if (!liveWinMode.CameraRunning)
{
lTRTCCloud.startLocalPreview(IntPtr.Zero);
liveWinMode.CameraRunning = true;
AddCustomVideoView(parent, CurrentClassroomEntity.TeacherId, TRTCVideoStreamType.TRTCVideoStreamTypeBig, true);
}
}
/// <summary>
/// 停止摄像头
/// </summary>
/// <param name="parent"></param>
public static void StopVideoMain(Panel parent)
{
var liveWinMode = CurrentLiveWindow.DataContext as LiveWindowViewModel;
if (liveWinMode.CameraRunning)
{
liveWinMode.CameraRunning = false;
lTRTCCloud.stopLocalPreview();
RemoveCustomVideoView(parent, CurrentClassroomEntity.TeacherId, TRTCVideoStreamType.TRTCVideoStreamTypeBig, true);
}
}
/// <summary>
/// 启动屏幕分享
/// </summary>
/// <param name="parent"></param>
public static void StartVideoSub(Panel parent)
{
var liveWinMode = CurrentLiveWindow.DataContext as LiveWindowViewModel;
if (!liveWinMode.ScreenRunning)
{
liveWinMode.ScreenRunning = true;
SelectVieoSub();
lTRTCCloud.startScreenCapture(IntPtr.Zero, TRTCVideoStreamType.TRTCVideoStreamTypeSub, settingWindowViewModel.EncParams);
AddCustomVideoView(parent, CurrentClassroomEntity.TeacherId, TRTCVideoStreamType.TRTCVideoStreamTypeSub, true);
}
}
/// <summary>
/// 停止屏幕分享
/// </summary>
/// <param name="parent"></param>
public static void StopVideoSub(Panel parent)
{
var liveWinMode = CurrentLiveWindow.DataContext as LiveWindowViewModel;
if (liveWinMode.ScreenRunning)
{
liveWinMode.ScreenRunning = false;
lTRTCCloud.stopScreenCapture();
RemoveCustomVideoView(parent, CurrentClassroomEntity.TeacherId, TRTCVideoStreamType.TRTCVideoStreamTypeSub, true);
}
}
/// <summary>
/// 选择要分享的屏幕
/// </summary>
public static void SelectVieoSub()
{
var liveWinMode = CurrentLiveWindow.DataContext as LiveWindowViewModel;
var current = liveWinMode.CurrentShareScreen;
var rect = new RECT();
var property = new TRTCScreenCaptureProperty();
lTRTCCloud.selectScreenCaptureTarget(ref current, ref rect, ref property);
}
/// <summary>
/// 添加自定义渲染 View 并绑定渲染回调
/// </summary>
@ -132,7 +193,9 @@ namespace JianGongYun.TRTC
videoView.SetRenderMode(settingWindowViewModel.RenderParams.fillMode);
videoView.Width = parent.ActualWidth;
videoView.Height = parent.ActualHeight;
parent.Children.Add(videoView);
parent.Dispatcher.Invoke(new Action(() => {
parent.Children.Add(videoView);
}));
string key = string.Format("{0}_{1}", userId, streamType);
VideoViews.Add(key, videoView);
}
@ -147,7 +210,9 @@ namespace JianGongYun.TRTC
if (VideoViews.TryGetValue(key, out videoView))
{
videoView.RemoveEngine(lTRTCCloud);
parent.Children.Remove(videoView);
parent.Dispatcher.Invoke(new Action(() => {
parent.Children.Remove(videoView);
}));
VideoViews.Remove(key);
}
}

View File

@ -0,0 +1,36 @@
using ManageLiteAV;
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Media.Imaging;
namespace JianGongYun.TRTC.Models
{
public class TRTCScreenEntity
{
//
// 摘要:
// 采集源类型
public TRTCScreenCaptureSourceType Type { get; set; }
//
// 摘要:
// 采集源ID对于窗口该字段指示窗口句柄对于屏幕该字段指示屏幕ID
public IntPtr SourceId { get; set; }
//
// 摘要:
// 采集源名称UTF8编码
public string SourceName { get; set; }
//
// 摘要:
// 缩略图内容
public WriteableBitmap Thumb { get; set; }
//
// 摘要:
// 图标内容
public WriteableBitmap Icon { get; set; }
/// <summary>
/// 源数据
/// </summary>
public TRTCScreenCaptureSourceInfo Info { get; set; }
}
}

View File

@ -1,12 +1,16 @@
using System;
using ManageLiteAV;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace JianGongYun.TRTC.Utils
{
public class Util
public static class Util
{
public static string UTF16To8(string str)
{
@ -71,5 +75,20 @@ namespace JianGongYun.TRTC.Utils
return strTime;
}
/// <summary>
/// 把trtc的图片buffer复制给wpf的writeableBitmap
/// </summary>
/// <param name="data"></param>
public static WriteableBitmap ToWriteableBitmap(this TRTCImageBuffer data)
{
var writeableBitmap = new WriteableBitmap((int)data.width, (int)data.height, 96, 96, PixelFormats.Pbgra32, null);
writeableBitmap.Lock();
Marshal.Copy(data.buffer, 0, writeableBitmap.BackBuffer, (int)data.length);
writeableBitmap.AddDirtyRect(new System.Windows.Int32Rect(0, 0, (int)data.width, (int)data.height));
writeableBitmap.Unlock();
return writeableBitmap;
}
}
}

View File

@ -1,10 +1,14 @@
using JianGongYun.TRTC.Models;
using JianGongYun.TRTC.Utils;
using ManageLiteAV;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text;
using System.Linq;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace JianGongYun.TRTC.ViewModels
@ -176,11 +180,11 @@ namespace JianGongYun.TRTC.ViewModels
private SIZE thumbSize = new SIZE { cx = 300, cy = 200 };
private SIZE iconSize = new SIZE { cx = 50, cy = 50 };
private ObservableCollection<TRTCScreenCaptureSourceInfo> _LiveScreens = new ObservableCollection<TRTCScreenCaptureSourceInfo>();
private ObservableCollection<TRTCScreenEntity> _LiveScreens = new ObservableCollection<TRTCScreenEntity>();
/// <summary>
/// 可分享桌面
/// </summary>
public ObservableCollection<TRTCScreenCaptureSourceInfo> LiveScreens
public ObservableCollection<TRTCScreenEntity> LiveScreens
{
get
{
@ -189,17 +193,55 @@ namespace JianGongYun.TRTC.ViewModels
var count = temp.getCount();
for (uint i = 0; i < count; i++)
{
_LiveScreens.Add(temp.getSourceInfo(i));
var info = temp.getSourceInfo(i);
//var icon = Util.ToWriteableBitmap(ref info.iconBGRA);
var thumb = info.thumbBGRA.ToWriteableBitmap();
_LiveScreens.Add(new TRTCScreenEntity { SourceId = info.sourceId, SourceName = info.sourceName, Type = info.type, Thumb = thumb, Info = info });
}
temp.release();
return _LiveScreens;
}
}
private IntPtr _CurrentShareScreen;
public IntPtr CurrentShareScreen
/// <summary>
/// 当前分享的桌面列表
/// </summary>
private bool _ShowShareScreenList = false;
public bool ShowShareScreenList
{
get { return _CurrentShareScreen; }
get
{
return _ShowShareScreenList;
}
set
{
_ShowShareScreenList = value;
if (_ShowShareScreenList)
{
var temp = LiveScreens;//获取一次刷新列表
}
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("ShowShareScreenList"));
}
}
}
/// <summary>
/// 当前分享的桌面
/// </summary>
private TRTCScreenCaptureSourceInfo _CurrentShareScreen;
public TRTCScreenCaptureSourceInfo CurrentShareScreen
{
get
{
if (_CurrentShareScreen == null && LiveScreens.Count > 0)
{
_CurrentShareScreen = LiveScreens[0].Info;
}
return _CurrentShareScreen;
}
set
{
_CurrentShareScreen = value;
@ -209,5 +251,6 @@ namespace JianGongYun.TRTC.ViewModels
}
}
}
}
}

View File

@ -7,7 +7,7 @@
xmlns:local="clr-namespace:JianGongYun.TRTC.Windows"
xmlns:live="clr-namespace:JianGongYun.TRTC"
mc:Ignorable="d"
Title="建工云课堂" MinWidth="600" MinHeight="350"
Title="建工云课堂" MinWidth="1000" MinHeight="650"
d:DesignHeight="1200" d:DesignWidth="1600"
BorderThickness="0" WindowStyle="None"
WindowStartupLocation="CenterOwner"
@ -21,7 +21,19 @@
<Geometry x:Key="Icon_User">M511.626 1.896C229.572 1.896 0.927 230.541 0.927 512.595c0 282.055 228.645 510.699 510.699 510.699s510.698-228.645 510.698-510.699S793.68 1.896 511.626 1.896z m0 69.641c243.606 0 441.058 197.474 441.058 441.058 0 87.347-25.392 168.762-69.194 237.271-73.419-77.609-170.944-132.204-280.597-151.829 70.004-33.755 118.404-105.164 118.404-188.066 0-115.388-93.535-208.922-208.923-208.922S303.452 294.583 303.452 409.97c0 82.902 48.399 154.311 118.403 188.066-110.093 19.704-207.96 74.661-281.479 152.77-44.177-68.704-69.808-150.465-69.808-238.211 0-243.584 197.496-441.058 441.058-441.058z</Geometry>
<BooleanToVisibilityConverter x:Key="VisibilityOfBool" />
<live:UnBooleanToVisibilityConverter x:Key="UnVisibilityOfBool" />
<!--直播方式数据类型转换-->
<live:LiveTypeToBoolConverter x:Key="LiveTypeConverter"></live:LiveTypeToBoolConverter>
<!--可分享屏幕自定义容器-->
<ControlTemplate x:Key="ShareListTemplate">
<WrapPanel IsItemsHost="True"></WrapPanel>
</ControlTemplate>
<!--可分享屏幕自定义选项-->
<DataTemplate x:Key="ShareListItemTemplate">
<StackPanel Orientation="Vertical" Width="300" Height="230" Background="#232428" Margin="5">
<Image Margin="10 5 10 0" Width="280" Height="200" Source="{Binding Thumb}"></Image>
<TextBlock HorizontalAlignment="Center" Width="280" TextAlignment="Left" TextTrimming="CharacterEllipsis" Text="{Binding Path=SourceName}" Foreground="White"></TextBlock>
</StackPanel>
</DataTemplate>
</Metro:MetroWindow.Resources>
<Canvas x:Name="Root" Background="Transparent">
<!--父容器填满-->
@ -69,8 +81,10 @@
</Canvas>
<!--中间面板-->
<Canvas x:Name="CusContent" Background="#151618">
<!--屏幕预览容器-->
<Grid x:Name="BeforeLiveSubViewWrap" Width="{Binding ElementName=CusContent,Path=ActualWidth}" Height="{Binding ElementName=CusContent,Path=ActualHeight}" Canvas.Top="0" Canvas.Left="0"></Grid>
<!--直播前-->
<Grid Canvas.Top="0" Canvas.Left="0" Height="{Binding ElementName=CusContent,Path=ActualHeight}" Width="{Binding ElementName=CusContent,Path=ActualWidth}" Visibility="{Binding IsLive, Converter={StaticResource UnVisibilityOfBool}}">
<Grid Canvas.Top="0" Canvas.Left="0" Background="#aa151618" Height="{Binding ElementName=CusContent,Path=ActualHeight}" Width="{Binding ElementName=CusContent,Path=ActualWidth}" Visibility="{Binding IsLive, Converter={StaticResource UnVisibilityOfBool}}">
<StackPanel Width="700" VerticalAlignment="Center">
<TextBlock FontSize="30" Foreground="#999999" HorizontalAlignment="Center">请选择授课方式</TextBlock>
<TextBlock HorizontalAlignment="Center" FontSize="16" Margin="0 10 0 0" Foreground="#999999">您可在上课期间随时调整授课方式</TextBlock>
@ -90,6 +104,7 @@
<Grid Width="{Binding ElementName=CameraPrew,Path=ActualWidth}" Height="{Binding ElementName=CameraPrew,Path=ActualHeight}" Canvas.Top="0" Canvas.Left="0">
<Path Margin="0 0 0 30" Width="111" Height="111" Fill="#cccccc" Shape.Stretch="Fill" Data="{StaticResource Icon_User}" />
</Grid>
<!--摄像头预览容器-->
<Grid x:Name="BeforeLiveViewWrap" Width="{Binding ElementName=CameraPrew,Path=ActualWidth}" Height="{Binding ElementName=CameraPrew,Path=ActualHeight}" Canvas.Top="0" Canvas.Left="0"></Grid>
<TextBlock Width="{Binding ElementName=CameraPrew,Path=ActualWidth}" Canvas.Bottom="0" Canvas.Left="0" Padding="5" FontSize="14" Foreground="#cccccc" Background="#65888888" TextAlignment="Center">摄像头预览</TextBlock>
</Canvas>
@ -133,25 +148,20 @@
</DockPanel>
<Grid x:Name="CountdownWrap" Visibility="Hidden" Canvas.Top="0" Canvas.Left="0" Background="Transparent" Panel.ZIndex="10" Height="{Binding ElementName=Root,Path=ActualHeight}" Width="{Binding ElementName=Root,Path=ActualWidth}"></Grid>
<Grid x:Name="ShareScreenListWrap" Visibility="Visible" Canvas.Top="0" Canvas.Left="0" Background="Transparent" Panel.ZIndex="5" Height="{Binding ElementName=Root,Path=ActualHeight}" Width="{Binding ElementName=Root,Path=ActualWidth}">
<!--可分享屏幕列表-->
<Grid x:Name="ShareScreenListWrap" Visibility="{Binding ShowShareScreenList, Converter={StaticResource VisibilityOfBool}}" Canvas.Top="0" Canvas.Left="0" Background="Transparent" Panel.ZIndex="5" Height="{Binding ElementName=Root,Path=ActualHeight}" Width="{Binding ElementName=Root,Path=ActualWidth}">
<Border Width="970" Height="530" BorderBrush="#efefef" BorderThickness="2" CornerRadius="5">
<Canvas x:Name="ScrollWrap" Width="970" Height="530" HorizontalAlignment="Center" VerticalAlignment="Center" Background="#f12f3035">
<!--标题-->
<StackPanel Width="{Binding ElementName=ScrollWrap,Path=ActualWidth}">
<TextBlock Foreground="White" FontSize="20" FontWeight="Bold" Padding="10" HorizontalAlignment="Center" VerticalAlignment="Center">请选择要分享的屏幕或窗口</TextBlock>
<TextBlock Foreground="White" FontSize="20" FontWeight="Bold" Padding="10" HorizontalAlignment="Center" VerticalAlignment="Center">请选择要分享的屏幕或前台窗口(上课期间可随时切换)</TextBlock>
</StackPanel>
<ScrollViewer Canvas.Right="0" Canvas.Top="50" Height="480" Width="{Binding ElementName=ScrollWrap,Path=ActualWidth}">
<WrapPanel>
<StackPanel Width="300" Height="200" Background="GreenYellow" Margin="10"></StackPanel>
<StackPanel Width="300" Height="200" Background="GreenYellow" Margin="10"></StackPanel>
<StackPanel Width="300" Height="200" Background="GreenYellow" Margin="10"></StackPanel>
<StackPanel Width="300" Height="200" Background="GreenYellow" Margin="10"></StackPanel>
<StackPanel Width="300" Height="200" Background="GreenYellow" Margin="10"></StackPanel>
<StackPanel Width="300" Height="200" Background="GreenYellow" Margin="10"></StackPanel>
<StackPanel Width="300" Height="200" Background="GreenYellow" Margin="10"></StackPanel>
<StackPanel Width="300" Height="200" Background="GreenYellow" Margin="10"></StackPanel>
</WrapPanel>
<!--列表视图-->
<ScrollViewer Style="{StaticResource CusScroll}" Canvas.Right="0" Canvas.Top="50" Height="480" Width="{Binding ElementName=ScrollWrap,Path=ActualWidth}">
<ListBox MouseUp="ShareList_Selected" SelectedValuePath="Info" SelectedValue="{Binding CurrentShareScreen}" ItemsSource="{Binding LiveScreens}" Template="{StaticResource ShareListTemplate}" ItemTemplate="{StaticResource ShareListItemTemplate}"></ListBox>
</ScrollViewer>
<Button Click="Setting_Btn_Click" Style="{StaticResource CusIconBtn}" Canvas.Right="10" Canvas.Top="0" Background="Transparent" BorderThickness="0">
<!--关闭按钮-->
<Button Click="CloseShareList_Click" Style="{StaticResource CusIconBtn}" Canvas.Right="10" Canvas.Top="0" Background="Transparent" BorderThickness="0">
<Button.Content>
<StackPanel>
<TextBlock FontSize="30" Foreground="#fff" Margin="0 0 0 0">×</TextBlock>

View File

@ -165,21 +165,40 @@ namespace JianGongYun.TRTC.Windows
switch (LiveWindowViewModel.LiveType)
{
case Models.LiveTypeEnum.CameraAndScreen:
LiveClassroom.StopVideoSub(BeforeLiveSubViewWrap);//停止屏幕分享(二次选择需要先停止分享,不然界面会卡死)
LiveWindowViewModel.ShowShareScreenList = true;
break;
case Models.LiveTypeEnum.OnlyScreen:
LiveClassroom.StopVideoSub(BeforeLiveSubViewWrap);//停止屏幕分享(二次选择需要先停止分享,不然界面会卡死)
LiveClassroom.StopVideoMain(BeforeLiveViewWrap); //停止摄像头分享
LiveWindowViewModel.ShowShareScreenList = true;
break;
case Models.LiveTypeEnum.OnlyCamera:
if (!LiveWindowViewModel.CameraRunning)
{
LiveClassroom.StartVideoMain(BeforeLiveViewWrap);
}
LiveClassroom.StopVideoSub(BeforeLiveSubViewWrap);//停止屏幕分享
LiveClassroom.StartVideoMain(BeforeLiveViewWrap);
break;
case Models.LiveTypeEnum.OnlyAudio:
LiveClassroom.StopVideoMain(BeforeLiveViewWrap);//停止摄像头分享
LiveClassroom.StopVideoSub(BeforeLiveSubViewWrap);//停止屏幕分享
break;
default:
break;
}
}
private void CloseShareList_Click(object sender, RoutedEventArgs e)
{
LiveWindowViewModel.ShowShareScreenList = false;
}
private void ShareList_Selected(object sender, RoutedEventArgs e)
{
CloseShareList_Click(sender, e);
LiveClassroom.StartVideoSub(BeforeLiveSubViewWrap);
if (LiveWindowViewModel.LiveType== Models.LiveTypeEnum.CameraAndScreen)
{
LiveClassroom.StartVideoMain(BeforeLiveViewWrap);
}
}
}
}