123
This commit is contained in:
parent
a63abac88a
commit
11e2abe241
|
|
@ -228,14 +228,16 @@ namespace JianGongYun.TRTC.Components
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//public event Action<WriteableBitmap> OnRenderVideoFrameHandler;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 渲染回调int width, int height, int rotation,WriteableBitmap image
|
/// 渲染回调byte[] data,int width, int height
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<WriteableBitmap> OnRenderVideoFrameHandler;
|
public event Action<byte[], int, int> OnRenderVideoFrameHandler;
|
||||||
public event Action OnViewRemove;
|
public event Action OnViewRemove;
|
||||||
|
|
||||||
private void RenderFillMode(DrawingContext dc, byte[] data, int width, int height, int rotation)
|
private void RenderFillMode(DrawingContext dc, byte[] data, int width, int height, int rotation)
|
||||||
{
|
{
|
||||||
|
OnRenderVideoFrameHandler?.Invoke(data, width, height);
|
||||||
int viewWidth = (int)this.ActualWidth, viewHeight = (int)this.ActualHeight;
|
int viewWidth = (int)this.ActualWidth, viewHeight = (int)this.ActualHeight;
|
||||||
PixelFormat pixelFormat = PixelFormats.Pbgra32;
|
PixelFormat pixelFormat = PixelFormats.Pbgra32;
|
||||||
int bytesPerPixel = (pixelFormat.BitsPerPixel + 7) / 8;
|
int bytesPerPixel = (pixelFormat.BitsPerPixel + 7) / 8;
|
||||||
|
|
@ -250,17 +252,6 @@ namespace JianGongYun.TRTC.Components
|
||||||
mWriteableBitmap.AddDirtyRect(mInt32Rect);
|
mWriteableBitmap.AddDirtyRect(mInt32Rect);
|
||||||
mWriteableBitmap.Unlock();
|
mWriteableBitmap.Unlock();
|
||||||
|
|
||||||
//var tt = ConvertWriteableBitmapToBitmapImage(mWriteableBitmap);
|
|
||||||
//OpenCvSharp.Mat result = OpenCvSharp.Extensions.BitmapConverter.ToMat(tt);
|
|
||||||
//tt.Dispose();
|
|
||||||
//result.Create(mWriteableBitmap.PixelHeight, mWriteableBitmap.PixelWidth, OpenCvSharp.MatType.CV_8UC4, 4);
|
|
||||||
//mWriteableBitmap.CopyPixels(Int32Rect.Empty, result.Data, data.Length, 4);
|
|
||||||
//LiveClassroom.bbb.Enqueue(result);
|
|
||||||
//result.ImWrite($"d:\\{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.png");
|
|
||||||
//var a = ConvertWriteableBitmapToBitmapImage(mWriteableBitmap);
|
|
||||||
//a.Save($"d:\\{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.png");
|
|
||||||
OnRenderVideoFrameHandler?.Invoke(mWriteableBitmap);
|
|
||||||
|
|
||||||
ImageBrush brush = new ImageBrush(mWriteableBitmap);
|
ImageBrush brush = new ImageBrush(mWriteableBitmap);
|
||||||
if (rotation > 0)
|
if (rotation > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -280,6 +271,7 @@ namespace JianGongYun.TRTC.Components
|
||||||
|
|
||||||
private void RenderFitMode(DrawingContext dc, byte[] data, int width, int height, int rotation)
|
private void RenderFitMode(DrawingContext dc, byte[] data, int width, int height, int rotation)
|
||||||
{
|
{
|
||||||
|
OnRenderVideoFrameHandler?.Invoke(data, width, height);
|
||||||
int viewWidth = (int)this.ActualWidth, viewHeight = (int)this.ActualHeight;
|
int viewWidth = (int)this.ActualWidth, viewHeight = (int)this.ActualHeight;
|
||||||
PixelFormat pixelFormat = PixelFormats.Pbgra32;
|
PixelFormat pixelFormat = PixelFormats.Pbgra32;
|
||||||
int bytesPerPixel = (pixelFormat.BitsPerPixel + 7) / 8;
|
int bytesPerPixel = (pixelFormat.BitsPerPixel + 7) / 8;
|
||||||
|
|
@ -287,9 +279,6 @@ namespace JianGongYun.TRTC.Components
|
||||||
if (mWriteableBitmap == null || mWriteableBitmap.PixelWidth != width || mWriteableBitmap.PixelHeight != height)
|
if (mWriteableBitmap == null || mWriteableBitmap.PixelWidth != width || mWriteableBitmap.PixelHeight != height)
|
||||||
{
|
{
|
||||||
mWriteableBitmap = new WriteableBitmap(width, height, 96, 96, pixelFormat, null);
|
mWriteableBitmap = new WriteableBitmap(width, height, 96, 96, pixelFormat, null);
|
||||||
//Mat result = new Mat();
|
|
||||||
//result.Create(mWriteableBitmap.PixelHeight, mWriteableBitmap.PixelWidth, MatType.CV_8U, 4);
|
|
||||||
//mWriteableBitmap.CopyPixels(Int32Rect.Empty, result.Data, (int)result.Step() * result.Rows, (int)result.Step());
|
|
||||||
mInt32Rect = new Int32Rect(0, 0, width, height);
|
mInt32Rect = new Int32Rect(0, 0, width, height);
|
||||||
}
|
}
|
||||||
mWriteableBitmap.Lock();
|
mWriteableBitmap.Lock();
|
||||||
|
|
@ -297,7 +286,7 @@ namespace JianGongYun.TRTC.Components
|
||||||
mWriteableBitmap.AddDirtyRect(mInt32Rect);
|
mWriteableBitmap.AddDirtyRect(mInt32Rect);
|
||||||
mWriteableBitmap.Unlock();
|
mWriteableBitmap.Unlock();
|
||||||
|
|
||||||
OnRenderVideoFrameHandler?.Invoke(mWriteableBitmap);
|
//OnRenderVideoFrameHandler?.Invoke(mWriteableBitmap);
|
||||||
|
|
||||||
ImageBrush brush = new ImageBrush(mWriteableBitmap);
|
ImageBrush brush = new ImageBrush(mWriteableBitmap);
|
||||||
if (rotation > 0)
|
if (rotation > 0)
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,18 @@ namespace JianGongYun.TRTC
|
||||||
private static LiveWindowViewModel liveWinMode;
|
private static LiveWindowViewModel liveWinMode;
|
||||||
public static ClassroomEntity CurrentClassroomEntity { get; private set; }
|
public static ClassroomEntity CurrentClassroomEntity { get; private set; }
|
||||||
public static TRTCCloudCallback TRTCCloudCallback = new TRTCCloudCallback();
|
public static TRTCCloudCallback TRTCCloudCallback = new TRTCCloudCallback();
|
||||||
|
/// <summary>
|
||||||
//private static ConcurrentBag<Task> VedioRecords = new ConcurrentBag<Task>();
|
/// 摄像头帧
|
||||||
|
/// </summary>
|
||||||
|
public static VideoFrameEntity MainFrame = new VideoFrameEntity();
|
||||||
|
/// <summary>
|
||||||
|
/// 屏幕帧
|
||||||
|
/// </summary>
|
||||||
|
public static VideoFrameEntity SubFrame = new VideoFrameEntity();
|
||||||
|
/// <summary>
|
||||||
|
/// 背景帧
|
||||||
|
/// </summary>
|
||||||
|
public static Mat BackgroundFrame = null;
|
||||||
//public static int UserCount = 999;
|
//public static int UserCount = 999;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 进入直播教室
|
/// 进入直播教室
|
||||||
|
|
@ -154,7 +164,21 @@ namespace JianGongYun.TRTC
|
||||||
var view = AddCustomVideoView(parent, CurrentClassroomEntity.TeacherId, TRTCVideoStreamType.TRTCVideoStreamTypeBig, true);
|
var view = AddCustomVideoView(parent, CurrentClassroomEntity.TeacherId, TRTCVideoStreamType.TRTCVideoStreamTypeBig, true);
|
||||||
if (liveWinMode.IsLive)
|
if (liveWinMode.IsLive)
|
||||||
{
|
{
|
||||||
VedioRecordTask(view, TRTCVideoStreamType.TRTCVideoStreamTypeBig);
|
//Stopwatch sw = new Stopwatch();
|
||||||
|
//VideoRecordTask(view, TRTCVideoStreamType.TRTCVideoStreamTypeBig);
|
||||||
|
view.OnRenderVideoFrameHandler += (data, w, h) =>
|
||||||
|
{
|
||||||
|
//sw.Restart();
|
||||||
|
lock (MainFrame)
|
||||||
|
{
|
||||||
|
MainFrame.Width = w;
|
||||||
|
MainFrame.Height = h;
|
||||||
|
MainFrame.Data = new byte[data.Length];
|
||||||
|
Buffer.BlockCopy(data, 0, MainFrame.Data, 0, data.Length);
|
||||||
|
}
|
||||||
|
//sw.Stop();
|
||||||
|
//Debug.Print("main" + sw.ElapsedMilliseconds.ToString());
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
@ -191,7 +215,21 @@ namespace JianGongYun.TRTC
|
||||||
var view = AddCustomVideoView(parent, CurrentClassroomEntity.TeacherId, TRTCVideoStreamType.TRTCVideoStreamTypeSub, true);
|
var view = AddCustomVideoView(parent, CurrentClassroomEntity.TeacherId, TRTCVideoStreamType.TRTCVideoStreamTypeSub, true);
|
||||||
if (liveWinMode.IsLive)
|
if (liveWinMode.IsLive)
|
||||||
{
|
{
|
||||||
VedioRecordTask(view, TRTCVideoStreamType.TRTCVideoStreamTypeSub);
|
//Stopwatch sw = new Stopwatch();
|
||||||
|
//VideoRecordTask(view, TRTCVideoStreamType.TRTCVideoStreamTypeSub);
|
||||||
|
view.OnRenderVideoFrameHandler += (data, w, h) =>
|
||||||
|
{
|
||||||
|
//sw.Restart();
|
||||||
|
lock (SubFrame)
|
||||||
|
{
|
||||||
|
SubFrame.Width = w;
|
||||||
|
SubFrame.Height = h;
|
||||||
|
SubFrame.Data = new byte[data.Length];
|
||||||
|
Buffer.BlockCopy(data, 0, SubFrame.Data, 0, data.Length);
|
||||||
|
}
|
||||||
|
//sw.Stop();
|
||||||
|
//Debug.Print("sub" + sw.ElapsedMilliseconds.ToString());
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
@ -270,77 +308,94 @@ namespace JianGongYun.TRTC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void VedioRecordTask(TXLiteAVVideoView view, TRTCVideoStreamType streamType)
|
public static void VideoRecordTask(ref Action onEnd)
|
||||||
{
|
{
|
||||||
var end = false;
|
var end = false;
|
||||||
Stopwatch sw1 = new Stopwatch();
|
onEnd = () =>
|
||||||
Stopwatch sw2 = new Stopwatch();
|
|
||||||
ConcurrentQueue<Mat> bitmaps = new ConcurrentQueue<Mat>();
|
|
||||||
view.OnRenderVideoFrameHandler += (b) =>
|
|
||||||
{
|
|
||||||
sw1.Restart();
|
|
||||||
bitmaps.Enqueue(b.ToMat());
|
|
||||||
sw1.Stop();
|
|
||||||
//Debug.Print("a" + sw1.Elapsed.TotalMilliseconds.ToString());
|
|
||||||
};
|
|
||||||
view.OnViewRemove += () =>
|
|
||||||
{
|
{
|
||||||
end = true;
|
end = true;
|
||||||
|
BackgroundFrame?.Dispose();
|
||||||
|
BackgroundFrame = null;
|
||||||
};
|
};
|
||||||
var task = Task.Factory.StartNew(() =>
|
var resolution = settingWindowViewModel.MainEncParams.videoResolution.ToString().Split('_');//屏幕分辨率
|
||||||
{
|
var fps = settingWindowViewModel.LiveFps;
|
||||||
Console.WriteLine($"VedioRecordTask Start {streamType}");
|
BackgroundFrame = new Mat(int.Parse(resolution[1]), int.Parse(resolution[2]), MatType.CV_8UC3, Scalar.FromRgb(0x20, 0x20, 0x20));
|
||||||
var _recoderDir = RecoderDir;
|
|
||||||
var imgTemp = Path.Combine(_recoderDir, $"{streamType}.png");
|
//Stopwatch sw1 = new Stopwatch();
|
||||||
var videoFile = Path.Combine(_recoderDir, $"{Util.TimeStr()}_{streamType}.avi");
|
//Stopwatch sw2 = new Stopwatch();
|
||||||
VideoWriter vw = new VideoWriter();
|
//ConcurrentQueue<Mat> bitmaps = new ConcurrentQueue<Mat>();
|
||||||
bool videoWriterInit = false;
|
//view.OnRenderVideoFrameHandler += (b) =>
|
||||||
var frameCount = 0;
|
//{
|
||||||
Timer timer = new Timer((a) =>
|
// sw1.Restart();
|
||||||
{
|
// bitmaps.Enqueue(b.ToMat());
|
||||||
//Console.WriteLine($"{streamType} fps {frameCount}");
|
// sw1.Stop();
|
||||||
Debug.Print($"{streamType} fps {frameCount}");
|
// //Debug.Print("a" + sw1.Elapsed.TotalMilliseconds.ToString());
|
||||||
Interlocked.Exchange(ref frameCount, 0);
|
//};
|
||||||
}, null, 0, 1000);
|
////view.OnRenderVideoFrameHandler1 += (a, b, c) =>
|
||||||
while (!end || bitmaps.Count > 0)
|
////{
|
||||||
{
|
//// var bb = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(a[0]) * a.Length);
|
||||||
if (bitmaps.Count == 0)
|
//// System.Runtime.InteropServices.Marshal.Copy(a, 0, bb, a.Length);
|
||||||
{
|
//// var mat = new Mat(c, b, MatType.CV_32SC4, bb);
|
||||||
Thread.Sleep(100);
|
//// mat.SaveImage("1.bmp");
|
||||||
continue;
|
////};
|
||||||
}
|
////view.OnViewRemove += () =>
|
||||||
if (bitmaps.TryDequeue(out var mat))
|
////{
|
||||||
{
|
//// end = true;
|
||||||
sw2.Restart();
|
////};
|
||||||
//mat.SaveImage(imgTemp);
|
//var task = Task.Factory.StartNew(() =>
|
||||||
|
//{
|
||||||
|
// Console.WriteLine($"VideoRecordTask Start {streamType}");
|
||||||
|
// var _recoderDir = RecoderDir;
|
||||||
|
// var imgTemp = Path.Combine(_recoderDir, $"{streamType}.png");
|
||||||
|
// var videoFile = Path.Combine(_recoderDir, $"{Util.TimeStr()}_{streamType}.avi");
|
||||||
|
// VideoWriter vw = new VideoWriter();
|
||||||
|
// bool videoWriterInit = false;
|
||||||
|
// var frameCount = 0;
|
||||||
|
// Timer timer = new Timer((a) =>
|
||||||
|
// {
|
||||||
|
// //Console.WriteLine($"{streamType} fps {frameCount}");
|
||||||
|
// Debug.Print($"{streamType} fps {frameCount}");
|
||||||
|
// Interlocked.Exchange(ref frameCount, 0);
|
||||||
|
// }, null, 0, 1000);
|
||||||
|
// while (!end || bitmaps.Count > 0)
|
||||||
|
// {
|
||||||
|
// if (bitmaps.Count == 0)
|
||||||
|
// {
|
||||||
|
// Thread.Sleep(100);
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// if (bitmaps.TryDequeue(out var mat))
|
||||||
|
// {
|
||||||
|
// sw2.Restart();
|
||||||
|
// //mat.SaveImage(imgTemp);
|
||||||
|
// //mat.Dispose();
|
||||||
|
// //mat = Cv2.ImRead(imgTemp, ImreadModes.AnyColor);
|
||||||
|
// //Cv2.ImShow(streamType.ToString(), mat);
|
||||||
|
// //Cv2.WaitKey(1);
|
||||||
|
// if (!videoWriterInit)
|
||||||
|
// {
|
||||||
|
// vw.Open(videoFile, FourCC.H264, settingWindowViewModel.LiveFps, mat.Size());
|
||||||
|
// videoWriterInit = true;
|
||||||
|
// }
|
||||||
|
// vw.Write(mat);
|
||||||
// mat.Dispose();
|
// mat.Dispose();
|
||||||
//mat = Cv2.ImRead(imgTemp, ImreadModes.AnyColor);
|
// Interlocked.Increment(ref frameCount);
|
||||||
//Cv2.ImShow(streamType.ToString(), mat);
|
// //Debug.Print("b"+sw2.Elapsed.TotalMilliseconds.ToString());
|
||||||
//Cv2.WaitKey(1);
|
// }
|
||||||
if (!videoWriterInit)
|
// else
|
||||||
{
|
// {
|
||||||
vw.Open(videoFile, FourCC.H264, settingWindowViewModel.LiveFps, mat.Size());
|
// Thread.Sleep(100);
|
||||||
videoWriterInit = true;
|
// }
|
||||||
}
|
// }
|
||||||
vw.Write(mat);
|
// vw?.Release();
|
||||||
mat.Dispose();
|
// vw?.Dispose();
|
||||||
Interlocked.Increment(ref frameCount);
|
// if (File.Exists(imgTemp))
|
||||||
//Debug.Print("b"+sw2.Elapsed.TotalMilliseconds.ToString());
|
// {
|
||||||
}
|
// File.Delete(imgTemp);
|
||||||
else
|
// }
|
||||||
{
|
// timer.Dispose();
|
||||||
Thread.Sleep(100);
|
// Console.WriteLine($"VideoRecordTask End {streamType}");
|
||||||
}
|
//}, TaskCreationOptions.LongRunning);
|
||||||
}
|
|
||||||
vw?.Release();
|
|
||||||
vw?.Dispose();
|
|
||||||
if (File.Exists(imgTemp))
|
|
||||||
{
|
|
||||||
File.Delete(imgTemp);
|
|
||||||
}
|
|
||||||
timer.Dispose();
|
|
||||||
Console.WriteLine($"VedioRecordTask End {streamType}");
|
|
||||||
}, TaskCreationOptions.LongRunning);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace JianGongYun.TRTC.Models
|
||||||
|
{
|
||||||
|
public class VideoFrameEntity
|
||||||
|
{
|
||||||
|
public byte[] Data { get; set; } = null;
|
||||||
|
public int Width { get; set; } = 0;
|
||||||
|
public int Height { get; set; } = 0;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -119,6 +119,7 @@ namespace JianGongYun.TRTC.Windows
|
||||||
{
|
{
|
||||||
var btn = sender as AduFlatButton;
|
var btn = sender as AduFlatButton;
|
||||||
var start = Convert.ToBoolean(btn.Tag);
|
var start = Convert.ToBoolean(btn.Tag);
|
||||||
|
Action onEnd = default;
|
||||||
if (start)//开始直播
|
if (start)//开始直播
|
||||||
{
|
{
|
||||||
if (SettingWindowViewModel.DiskSize <= ViewModels.SettingWindowViewModel.DiskWarningSize)
|
if (SettingWindowViewModel.DiskSize <= ViewModels.SettingWindowViewModel.DiskWarningSize)
|
||||||
|
|
@ -157,12 +158,14 @@ namespace JianGongYun.TRTC.Windows
|
||||||
}
|
}
|
||||||
LiveClassroom.StartMic();
|
LiveClassroom.StartMic();
|
||||||
LiveClassroom.SetMicMute(false);
|
LiveClassroom.SetMicMute(false);
|
||||||
|
LiveClassroom.VideoRecordTask(ref onEnd);//启动录制
|
||||||
|
|
||||||
}, SettingWindowViewModel.ScreenRecordingCountdown);
|
}, SettingWindowViewModel.ScreenRecordingCountdown);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LiveWindowViewModel.IsLive = start;
|
LiveWindowViewModel.IsLive = start;
|
||||||
|
onEnd?.Invoke();
|
||||||
//停止直播
|
//停止直播
|
||||||
LiveClassroom.StopMic();
|
LiveClassroom.StopMic();
|
||||||
LiveClassroom.StopVideoMain(AfterLiveViewWrap);
|
LiveClassroom.StopVideoMain(AfterLiveViewWrap);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue