From 4fc0d3bff2f0f3791f840675f495a83d201905f9 Mon Sep 17 00:00:00 2001 From: lxmou666 <772765102@qq.com> Date: Thu, 7 Jan 2021 00:25:33 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9B=B4=E6=92=AD=E5=AE=8C=E7=BB=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- JianGongYun/TRTC/LiveClassroom.cs | 150 ++++++++++++-------- JianGongYun/TRTC/Windows/LiveWindow.xaml.cs | 10 +- 2 files changed, 101 insertions(+), 59 deletions(-) diff --git a/JianGongYun/TRTC/LiveClassroom.cs b/JianGongYun/TRTC/LiveClassroom.cs index 6b610de..0bcc90d 100644 --- a/JianGongYun/TRTC/LiveClassroom.cs +++ b/JianGongYun/TRTC/LiveClassroom.cs @@ -19,6 +19,7 @@ using System.Windows.Data; using System.Drawing; using System.Diagnostics; using System.Runtime.InteropServices; +using AduSkin.Controls.Metro; namespace JianGongYun.TRTC { @@ -122,6 +123,37 @@ namespace JianGongYun.TRTC } private static string _RecoderDir; + + /// + /// 音频录制文件 + /// + public static string AudioTempPath + { + get + { + return Path.Combine(RecoderDir, $"temp_audio.aac"); + } + } + /// + /// 视频录制文件 + /// + public static string VideoTempPath + { + get + { + return Path.Combine(RecoderDir, $"temp_video.avi"); + } + } + /// + /// 合并后的文件 + /// + public static string ResultFilePath + { + get + { + return Path.Combine(RecoderDir, $"result.avi"); + } + } /// /// 录制内容的具体路径 /// @@ -272,6 +304,7 @@ namespace JianGongYun.TRTC StartRecordAudio(); } } + /// /// 录音 /// @@ -280,7 +313,7 @@ namespace JianGongYun.TRTC if (liveWinMode.IsLive && !liveWinMode.AudioRecordRunning) { liveWinMode.AudioRecordRunning = true; - var pars = new TRTCAudioRecordingParams { filePath = Path.Combine(RecoderDir, $"temp_audio.aac") }; + var pars = new TRTCAudioRecordingParams { filePath = AudioTempPath }; lTRTCCloud.startAudioRecording(ref pars); } } @@ -325,7 +358,6 @@ namespace JianGongYun.TRTC BackgroundFrame = new Mat(int.Parse(resolution[2]), int.Parse(resolution[1]), MatType.CV_8UC4, backColor);//合成双路视频的背景 var delay = 1000 / (int)fps;//每帧时间 var _recoderDir = RecoderDir; - var videoFile = Path.Combine(_recoderDir, $"temp_video.avi"); //var videoFrameTemp = Path.Combine(_recoderDir, $"videoFrameTemp.bmp"); var backHeight = BackgroundFrame.Rows;//画面高度 var backWidth = BackgroundFrame.Cols;//画面宽度 @@ -336,17 +368,17 @@ namespace JianGongYun.TRTC ConcurrentQueue mats = new ConcurrentQueue(); - //int runFps = 0;//实时帧 - //Timer timer = new Timer((a) => - //{ - // Debug.Print($"runFps {runFps}. leavingsMat {mats.Count}."); - // Interlocked.Exchange(ref runFps, 0); - //}, null, 0, 1000); + int runFps = 0;//实时帧 + Timer timer = new Timer((a) => + { + Debug.Print($"runFps {runFps}. leavingsMat {mats.Count}."); + Interlocked.Exchange(ref runFps, 0); + }, null, 0, 1000); onEnd = () => { end = true; - //timer.Dispose(); + timer.Dispose(); }; //帧合并线程 @@ -422,7 +454,7 @@ namespace JianGongYun.TRTC } } - Skip1: + Skip1: if (liveWinMode.CameraRunning)//摄像头分享中 { @@ -450,34 +482,35 @@ namespace JianGongYun.TRTC } } - Skip2: + Skip2: mats.Enqueue(BackgroundFrame.CvtColor(ColorConversionCodes.BGRA2BGR)); - //Interlocked.Increment(ref runFps); + Interlocked.Increment(ref runFps); stopwatch.Stop(); - var sleep = delay - (int)stopwatch.ElapsedMilliseconds;//每帧时间减去每帧处理时间为sleep时间 - //if (sleep < 0)//如果处理时间超过了每帧时间,记录下来 - //{ - // delayEqualize += sleep; - //} - //if (delayEqualize < 0 && sleep > 0) - //{ - // delayEqualize += sleep; - // if (delayEqualize > 0) - // { - // delayEqualize = 0; - // } - //} - //var lastsleep = sleep + delayEqualize;//理论休眠时间再去掉补偿时间 - //Debug.Print($"video frame run {stopwatch.ElapsedMilliseconds}. lastsleep {lastsleep}. sum {(stopwatch.ElapsedMilliseconds + lastsleep)}"); - //if (lastsleep > 0) - //{ - // Thread.Sleep(lastsleep); - //} - if (liveWinMode.IsLive && sleep > 0) + var sleep = delay - (int)stopwatch.ElapsedMilliseconds - 1;//每帧时间减去每帧处理时间为sleep时间//视频实际时长偏短,再减1是微调 + if (sleep > 0) { - Thread.Sleep(sleep); + if (delayEqualize == 0) + { + Thread.Sleep(sleep); + continue; + } + else + { + delayEqualize += sleep; + if (delayEqualize > 0) + { + Thread.Sleep(delayEqualize); + delayEqualize = 0; + continue; + } + } } + else if (sleep < 0)//如果处理时间超过了每帧时间,记录下来 + { + delayEqualize += sleep; + } + //Debug.Print($"video frame run {stopwatch.ElapsedMilliseconds}. sleep{sleep}. delayEqualize {delayEqualize}. delay {delay}."); } BackgroundFrame?.Dispose(); BackgroundFrame = null; @@ -487,9 +520,8 @@ namespace JianGongYun.TRTC //新开线程写文件,减少帧处理时间 Task.Factory.StartNew(() => { - var delayEqualize = 0;//每帧时间补偿,在性能和其他因素影响下delay的时间不一定充足 - VideoWriter vw = new VideoWriter(videoFile, FourCC.H264, fps, BackgroundFrame.Size()); - Stopwatch stopwatch = new Stopwatch();//计时器 + VideoWriter vw = new VideoWriter(VideoTempPath, FourCC.H264, fps, BackgroundFrame.Size()); + //Stopwatch stopwatch = new Stopwatch();//计时器 Debug.Print("开始写入视频线程"); while (!end || mats.Count > 0) { @@ -497,29 +529,11 @@ namespace JianGongYun.TRTC { if (mats.TryDequeue(out var frame)) { - stopwatch.Restart(); + //stopwatch.Restart(); vw.Write(frame); frame.Dispose(); - stopwatch.Stop(); - Debug.Print($"video frame write {stopwatch.ElapsedMilliseconds}"); - //var sleep = delay - (int)stopwatch.ElapsedMilliseconds;//每帧时间减去每帧处理时间为sleep时间 - //if (sleep < 0)//如果处理时间超过了每帧时间,记录下来 - //{ - // delayEqualize += sleep; - //} - //if (delayEqualize < 0 && sleep > 0) - //{ - // delayEqualize += sleep; - // if (delayEqualize > 0) - // { - // delayEqualize = 0; - // } - //} - //var lastsleep = sleep + delayEqualize;//理论休眠时间再去掉补偿时间 - //if (lastsleep > 0) - //{ - // Thread.Sleep(lastsleep); - //} + //stopwatch.Stop(); + //Debug.Print($"video frame write {stopwatch.ElapsedMilliseconds}"); } else { @@ -532,6 +546,28 @@ namespace JianGongYun.TRTC } } vw.Dispose(); + //合并视频 + var arguments = $@"-i ""{VideoTempPath}"" -i ""{AudioTempPath}"" -c:v copy -c:a copy -strict experimental -y ""{ResultFilePath}"""; + Process prc = new Process { StartInfo = new ProcessStartInfo { FileName = Path.Combine(Environment.CurrentDirectory, "ffmpeg.exe"), Arguments = arguments, CreateNoWindow = true, UseShellExecute = false } }; + prc.Start(); + prc.WaitForExit(); + if (File.Exists(VideoTempPath)) + { + File.Delete(VideoTempPath); + } + if (File.Exists(AudioTempPath)) + { + File.Delete(AudioTempPath); + } + CurrentLiveWindow.Dispatcher.Invoke(new Action(() => + { + NoticeManager.NotifiactionShow.AddNotifiaction(new NotifiactionModel() + { + Title = "提醒", + Content = $"成功保存直播视频,路径:{ResultFilePath}。", + NotifiactionType = AduSkin.Controls.EnumPromptType.Success + }); + })); Debug.Print("结束写入视频线程"); }, TaskCreationOptions.LongRunning); diff --git a/JianGongYun/TRTC/Windows/LiveWindow.xaml.cs b/JianGongYun/TRTC/Windows/LiveWindow.xaml.cs index 032a938..5066cfb 100644 --- a/JianGongYun/TRTC/Windows/LiveWindow.xaml.cs +++ b/JianGongYun/TRTC/Windows/LiveWindow.xaml.cs @@ -52,14 +52,20 @@ namespace JianGongYun.TRTC.Windows Rad2.Foreground = color; Rad3.Foreground = color; Rad4.Foreground = color; - LiveClassroom.PauseAllView(false);//切前台启动实时预览渲染 + if (LiveWindowViewModel.IsLive) + { + LiveClassroom.PauseAllView(false);//切前台启动实时预览渲染 + } } protected override void OnDeactivated(EventArgs e) { base.OnDeactivated(e); - LiveClassroom.PauseAllView(true);//切后台停止实时预览渲染 + if (LiveWindowViewModel.IsLive) + { + LiveClassroom.PauseAllView(true);//切后台停止实时预览渲染 + } } private Window settingWindow;