using NAudio.MediaFoundation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Threading.Tasks;
namespace ISCamRecorder {
class H264Writer
{
private IMFSinkWriter _writer;
private int _streamIndex;
public H264Writer( string path, TIS.Imaging.FrameType inputType, int fps, int bitrate )
{
System.Diagnostics.Debug.Assert(inputType.Subtype == TIS.Imaging.MediaSubtypes.RGB32);
CreateWriter(path, inputType.Width, inputType.Height, fps, bitrate);
}
private void CreateWriter(string path, int width, int height, int fps, int bitrate)
{
var MFVideoFormat_RGB32 = new Guid("00000016-0000-0010-8000-00AA00389B71");
var MFVideoFormat_H264 = new Guid("34363248-0000-0010-8000-00AA00389B71");
var MF_MT_INTERLACE_MODE = new Guid("e2724bb8-e676-4806-b4b2-a8d6efb44ccd");
var MFVideoInterlace_Progressive = 2;
var MF_MT_FRAME_SIZE = new Guid("1652c33d-d6b2-4012-b834-72030849a37d");
var MF_MT_FRAME_RATE = new Guid("c459a2e8-3d2c-4e44-b132-fee5156c7bb0");
var MF_MT_PIXEL_ASPECT_RATIO = new Guid("c6376a1e-8d0a-4027-be45-6d9a0ad39bb6");
MediaFoundationInterop.MFCreateSinkWriterFromURL(path, null, null, out _writer);
MediaFoundationInterop.MFCreateMediaType(out IMFMediaType outType);
outType.SetGUID(MediaFoundationAttributes.MF_MT_MAJOR_TYPE, MediaTypes.MFMediaType_Video);
outType.SetGUID(MediaFoundationAttributes.MF_MT_SUBTYPE, MFVideoFormat_H264);
outType.SetUINT32(MediaFoundationAttributes.MF_MT_AVG_BITRATE, bitrate);
outType.SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
outType.SetUINT64(MF_MT_FRAME_SIZE, ((long)width) << 32 | (long)height);
outType.SetUINT64(MF_MT_FRAME_RATE, ((long)fps) << 32 | (long)1);
outType.SetUINT64(MF_MT_PIXEL_ASPECT_RATIO, ((long)1) << 32 | (long)1);
_writer.AddStream(outType, out _streamIndex);
MediaFoundationInterop.MFCreateMediaType(out IMFMediaType inType);
inType.SetGUID(MediaFoundationAttributes.MF_MT_MAJOR_TYPE, MediaTypes.MFMediaType_Video);
inType.SetGUID(MediaFoundationAttributes.MF_MT_SUBTYPE, MFVideoFormat_RGB32);
inType.SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
inType.SetUINT64(MF_MT_FRAME_SIZE, ((long)width) << 32 | (long)height);
inType.SetUINT64(MF_MT_FRAME_RATE, ((long)fps) << 32 | (long)1);
inType.SetUINT64(MF_MT_PIXEL_ASPECT_RATIO, ((long)1) << 32 | (long)1);
_writer.SetInputMediaType(_streamIndex, inType, null);
}
public void Begin()
{
_writer.BeginWriting();
}
[System.Runtime.InteropServices.DllImport("mfplat.dll", ExactSpelling = true, PreserveSig = false)]
private static extern void MFCopyImage(IntPtr pDest, int lDestStride, IntPtr pSrc, int lSrcStride, uint dwWidthInBytes, uint dwLines);
private void WriteFrame(IntPtr data, int width, int height, long ts, long dt)
{
int stride = width * 4;
int cbBuffer = stride * height;
MediaFoundationInterop.MFCreateMemoryBuffer(cbBuffer, out IMFMediaBuffer buffer);
buffer.Lock(out IntPtr ptr, out int maxLength, out int currentLength);
MFCopyImage(ptr, stride, data, stride, (uint)stride, (uint)height);
buffer.Unlock();
buffer.SetCurrentLength(cbBuffer);
MediaFoundationInterop.MFCreateSample(out IMFSample sample);
sample.AddBuffer(buffer);
sample.SetSampleTime(ts);
sample.SetSampleDuration(dt);
_writer.WriteSample(_streamIndex, sample);
System.Runtime.InteropServices.Marshal.ReleaseComObject(sample);
System.Runtime.InteropServices.Marshal.ReleaseComObject(buffer);
}
public void Write( TIS.Imaging.IFrameQueueBuffer buffer )
{
long ts = (long)(buffer.FrameMetadata.SampleStartTime * 10000000);
long dt = (long)((buffer.FrameMetadata.SampleEndTime - buffer.FrameMetadata.SampleStartTime) * 10000000);
WriteFrame(buffer.GetIntPtr(), buffer.FrameType.Width, buffer.FrameType.Height, ts, dt);
}
public void End()
{
_writer.DoFinalize();
}
}
}