-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into fix_tcp_socket_crash
- Loading branch information
Showing
36 changed files
with
751 additions
and
247 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace BocchiTracker.Config.Parts | ||
{ | ||
public class CaptureSetting | ||
{ | ||
public GameCaptureType GameCaptureType { get; set; } = GameCaptureType.NotUse; | ||
|
||
public SIPSorceryMedia.Abstractions.VideoCodecsEnum VideoCodecs { get; set; } = SIPSorceryMedia.Abstractions.VideoCodecsEnum.VP8; | ||
|
||
public bool IncludeAudio = false; | ||
|
||
public int RecordingFrameRate { get; set; } = 30; | ||
|
||
public int RecordingMintes { get; set; } = 3; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace BocchiTracker.Config.Parts | ||
{ | ||
public class ExternalToolsPath | ||
{ | ||
public string? ProcDumpPath { get; set; } | ||
|
||
public string? FFmpegPath { get; set; } | ||
} | ||
} |
155 changes: 133 additions & 22 deletions
155
Application/Models/GameCaptureRTC/CaptureFrameStorage.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,155 @@ | ||
| ||
using BocchiTracker.ModelEvent; | ||
using FFMpegCore; | ||
using OpenCvSharp; | ||
using Prism.Events; | ||
using SixLabors.ImageSharp; | ||
using SixLabors.ImageSharp.PixelFormats; | ||
using System; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Runtime.InteropServices; | ||
using System.Text.RegularExpressions; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace BocchiTracker.GameCaptureRTC | ||
{ | ||
public class CaptureFrameStorage | ||
public class CaptureFrameStorage : IDisposable | ||
{ | ||
private int _frameRate = 30; | ||
private int _recordingMaxFrames = 0; | ||
public ModelEvent.CaptureStreamParameter CaptureStreamParameter { get; set; } = new ModelEvent.CaptureStreamParameter(); | ||
private object _mutext = new object(); | ||
|
||
public CaptureFrameStorage(int inFrameRate, int inRecordingMintes) | ||
private int _maxRecordingFrameCount = 0; | ||
private int _maxSplitFrameCount = 0; | ||
private int _curFrameCount = 0; | ||
private int _curSpliteFrameCount = 0; | ||
|
||
private string _tempCancatMovieDirectory = Path.Combine(Path.GetTempPath(), "BocchiTracker", "temp", "concat_movies"); | ||
private string _tempMovieDirectory = Path.Combine(Path.GetTempPath(), "BocchiTracker", "temp", "movies"); | ||
private string _tempPicsDirectory = Path.Combine(Path.GetTempPath(), "BocchiTracker", "temp", "pics"); | ||
|
||
private int _movieID = 0; | ||
private int _adjustedwidth = 640; | ||
private int _adjustedHeight = 480; | ||
|
||
private VideoWriter _videoWriter = default!; | ||
|
||
public CaptureFrameStorage(string inFFmpegPath, int inMaxRecordingFrameCount, int inMaxSplitFrameCount) | ||
{ | ||
_frameRate = inFrameRate; | ||
_recordingMaxFrames = (inRecordingMintes * 60) * _frameRate; | ||
GlobalFFOptions.Configure(options => options.BinaryFolder = inFFmpegPath); | ||
|
||
_maxSplitFrameCount = inMaxSplitFrameCount; | ||
_maxRecordingFrameCount = inMaxRecordingFrameCount; | ||
|
||
if (!Directory.Exists(_tempMovieDirectory)) | ||
Directory.CreateDirectory(_tempMovieDirectory); | ||
if (!Directory.Exists(_tempCancatMovieDirectory)) | ||
Directory.CreateDirectory(_tempCancatMovieDirectory); | ||
if (!Directory.Exists(_tempPicsDirectory)) | ||
Directory.CreateDirectory(_tempPicsDirectory); | ||
|
||
Cleanup(); | ||
} | ||
|
||
public void AddFrame(int inWidth, int inHeight, int inStride, nint inData) | ||
{ | ||
if (CaptureStreamParameter.Frames.Count > _recordingMaxFrames) | ||
CaptureStreamParameter.Frames.RemoveAt(0); | ||
|
||
// メモリ領域のコピーを作成して渡す | ||
byte[] dataCopy = new byte[inHeight * inStride]; | ||
unsafe | ||
lock(_mutext) | ||
{ | ||
byte* src = (byte*)inData; | ||
for (int i = 0; i < dataCopy.Length; i++) | ||
if(_adjustedwidth > inWidth || _adjustedwidth == 0) | ||
_adjustedwidth = inWidth % 2 == 0 ? inWidth : inWidth - 1; | ||
if (_adjustedHeight > inHeight || _adjustedHeight == 0) | ||
_adjustedHeight = inHeight % 2 == 0 ? inHeight : inHeight - 1; | ||
|
||
if (_curSpliteFrameCount == 0) | ||
{ | ||
System.Console.WriteLine("start video capture"); | ||
if (_videoWriter == null || _videoWriter.IsDisposed) | ||
_videoWriter = new VideoWriter(); | ||
_videoWriter.Open(Path.Combine(_tempMovieDirectory, $"movie.{_movieID}.mp4"), FourCC.MPG4, 30, new OpenCvSharp.Size(inWidth, inHeight)); | ||
++_movieID; | ||
} | ||
|
||
unsafe | ||
{ | ||
byte[] dataCopy = new byte[inHeight * inStride]; | ||
unsafe | ||
{ | ||
byte* src = (byte*)inData; | ||
for (int i = 0; i < dataCopy.Length; i++) | ||
{ | ||
dataCopy[i] = *(src + i); | ||
} | ||
} | ||
|
||
using (var mat = new Mat(inHeight, inWidth, MatType.CV_8UC3, dataCopy, inStride)) | ||
{ | ||
_videoWriter.Write(mat); | ||
|
||
_curFrameCount++; | ||
_curSpliteFrameCount++; | ||
} | ||
} | ||
|
||
if (_curSpliteFrameCount > _maxSplitFrameCount) | ||
{ | ||
dataCopy[i] = *(src + i); | ||
System.Console.WriteLine("_videoWriter wrote maximum frame, so next video..."); | ||
_curSpliteFrameCount = 0; | ||
_videoWriter.Dispose(); | ||
} | ||
|
||
if (_curFrameCount > _maxRecordingFrameCount) | ||
{ | ||
var bochi_files = Directory.GetFiles(_tempMovieDirectory, "*.mp4") | ||
.OrderBy(file => int.Parse(Regex.Match(file, @"(?<=movie\.)(\d+)(?=\.mp4)").Value)) | ||
.ToList(); | ||
if(bochi_files.Any()) | ||
{ | ||
System.Console.WriteLine("the maximum recording time has been exceeded, so remove old video file"); | ||
File.Delete(bochi_files[0]); | ||
} | ||
_curFrameCount -= _maxSplitFrameCount; | ||
} | ||
} | ||
} | ||
|
||
CaptureStreamParameter.Frames.Add(new ModelEvent.CaptureStreamParameter.Frame | ||
public string ConcatMovie() | ||
{ | ||
lock (_mutext) | ||
{ | ||
Data = dataCopy, | ||
Width = inWidth, | ||
Height = inHeight, | ||
Stride = inStride, | ||
}); | ||
Dispose(); | ||
_curFrameCount = 0; | ||
_curSpliteFrameCount = 0; | ||
|
||
var output = Path.Combine(_tempCancatMovieDirectory, "bocchi_movie.mp4"); | ||
var bochi_files = Directory.GetFiles(_tempMovieDirectory, "*.mp4"); | ||
if (!bochi_files.Any()) | ||
return string.Empty; | ||
|
||
var command = FFMpegArguments | ||
.FromDemuxConcatInput(bochi_files) | ||
.OutputToFile(output, overwrite: true, op => op.Resize(_adjustedwidth, _adjustedHeight)); | ||
bool ret = command.ProcessSynchronously(); | ||
if (ret) | ||
Cleanup(); | ||
return output; | ||
} | ||
} | ||
|
||
public void Cleanup() | ||
{ | ||
var bochi_files = Directory.GetFiles(_tempMovieDirectory, "*.mp4"); | ||
foreach (var file in bochi_files) | ||
{ | ||
File.Delete(file); | ||
} | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
if (_videoWriter != null && !_videoWriter.IsDisposed) | ||
{ | ||
_videoWriter.Dispose(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.