var mp4_codec = Config.Media.OutputVideoCodec;
var fps = Config.Media.OutputVideoFps;
// win2dで描画する為の準備
ControlAccess.UCPlayerPanel?.GetFrameStart();
// 描画サイズ取得用にフレームを取得
using var frameSize = ControlAccess.UCPlayerPanel?.GetFrame( 0 );
if ( frameSize == null )
{
Log.Error( $"get frame failure.", true );
return;
}
using var mp4 = new Mp4IO();
var bmp = mp4.Open
(
aFilePath,
mp4_codec,
fps,
(int)frameSize.Size.Width,
(int)frameSize.Size.Height
);
if ( bmp == null )
{
Log.Error( $"open video file failure.", true );
return;
}
var frameTime = 1d / fps;
await Task.Run
(
() =>
{
for ( var time = 0D; time <= DmsControl.EndPlayTime; time += frameTime )
{
// 指定時間のフレーム画像取得(CanvasBitmap)
using var frame = ControlAccess.UCPlayerPanel?.GetFrame( time );
if ( frame == null )
{
Log.Error( $"frame read error.[{time}]" );
continue;
}
var buffer = frame.GetPixelBytes();
var bmpData = bmp.LockBits
(
new( 0, 0, bmp.Width, bmp.Height ),
ImageLockMode.WriteOnly,
bmp.PixelFormat
);
// Bitmapへ書込み
Marshal.Copy( buffer, 0, bmpData.Scan0, buffer.Length );
bmp.UnlockBits( bmpData );
// MP4へのフレーム追加
mp4.AddFrame();
}
}
public CanvasBitmap? GetFrame( double aFrameTime )
{
if ( _Offscreen == null )
{
return null;
}
try
{
// フレーム処理
_PlayerSurface?.OnMove( aFrameTime );
// 描画処理
using var drawSession = _Offscreen.CreateDrawingSession();
drawSession.Clear( DrawSet.SheetColor.Color );
_PlayerSurface?.OnDraw( new CanvasDrawEventArgs( drawSession ) );
// CanvasBitmap作成
return CanvasBitmap.CreateFromBytes
(
drawSession,
_Offscreen.GetPixelBytes( 0, 0, (int)_Offscreen.SizeInPixels.Width, (int)_Offscreen.SizeInPixels.Height ),
(int)_Offscreen.SizeInPixels.Width,
(int)_Offscreen.SizeInPixels.Height,
DirectXPixelFormat.R8G8B8A8UIntNormalized,
96,
CanvasAlphaMode.Premultiplied
);
}
catch ( Exception e )
{
Log.Error( $"{Log.GetThisMethodName}:{e.Message}" );
return null;
}
}
using System.Drawing;
using System.Drawing.Imaging;
using OpenCvSharp;
/// <summary>
/// MP4出力
/// </summary>
internal class Mp4IO : DisposeBaseClass
{
/// <summary>
/// Video書込
/// </summary>
private VideoWriter? _Writer = null;
/// <summary>
/// 画像コンバーター
/// </summary>
private readonly ImageConverter _Converter = new();
/// <summary>
/// フレーム書込用Bitmap
/// </summary>
private Bitmap? _Bmp = null;
/// <summary>
/// ファイルオープン
/// </summary>
/// <param name="aGeneralPath">出力ファイルパス</param>
/// <param name="aCodec">MP4コーデック</param>
/// <param name="aFrameRate">フレームレート</param>
/// <param name="aWidth">映像横幅</param>
/// <param name="aHeight">映像高さ</param>
/// <returns>映像書込用のBitmap</returns>
public Bitmap Open( GeneralPath aGeneralPath, string aCodec, int aFrameRate, int aWidth, int aHeight )
{
Close();
// MP4出力用のストリームを作成
_Writer = new VideoWriter
(
aGeneralPath.AbsoulteFilePath,
string.IsNullOrEmpty( aCodec ) ? FourCC.Default : FourCC.FromString( aCodec ),
aFrameRate,
new( aWidth, aHeight )
);
// フレーム書込み用のBitmap作成
_Bmp = new Bitmap( aWidth, aHeight, PixelFormat.Format32bppArgb );
return _Bmp;
}
/// <summary>
/// フレーム追加
/// </summary>
/// <returns>True:書込成功、False:書込失敗</returns>
public bool AddFrame()
{
if ( _Writer == null || _Bmp == null )
{
return false;
}
var bmpData = _Bmp.LockBits
(
new( 0, 0, _Bmp.Width, _Bmp.Height ),
ImageLockMode.ReadOnly,
_Bmp.PixelFormat
);
var buffer = (byte[]?)_Converter.ConvertTo( _Bmp, typeof( byte[] ) );
if ( buffer == null )
{
return false;
}
// 多分、ここで色情報の置き換えを行っている
using var mat = Mat.FromImageData( buffer ).CvtColor( ColorConversionCodes.RGBA2RGB );
// using var mat = Mat.FromImageData( buffer ).CvtColor( ColorConversionCodes.RGB2BGR );
_Writer.Write( mat );
_Bmp.UnlockBits( bmpData );
return true;
}
/// <summary>
/// ファイルクローズ
/// </summary>
public void Close()
{
_Writer?.Dispose();
_Writer = null;
_Bmp?.Dispose();
_Bmp = null;
}
}