/// <inheritdoc /> /// <summary> /// Encodes a video frame. /// </summary> /// <param name="data">Bitmap data.</param> /// <param name="time">Time in ticks.</param> /// <param name="stream">Output stream.</param> public void Encode(BitmapData data, long time, Stream stream) { // create sample Sample sample = MediaFactory.CreateSample(); MediaBuffer buffer; if (this.surface == null) { // create buffer MediaFactory.Create2DMediaBuffer( data.Width, data.Height, new FourCC((int)Format.X8R8G8B8), new RawBool(false), out buffer); // calculate length buffer.CurrentLength = data.Stride * data.Height; // copy data Utilities.CopyMemory(buffer.Lock(out _, out _), data.Scan0, buffer.CurrentLength); // unlock bits buffer.Unlock(); } else { // create buffer MediaFactory.CreateDXGISurfaceBuffer(typeof(Texture2D).GUID, this.surface, 0, new RawBool(false), out buffer); // set buffer length buffer.CurrentLength = buffer.QueryInterface <Buffer2D>().ContiguousLength; } // add buffer to sample sample.AddBuffer(buffer); sample.SampleTime = time; try { this.sinkWriter.WriteSample(this.streamIdx, sample); } catch (SharpDXException) { } finally { buffer.Dispose(); sample.Dispose(); } }
/// <inheritdoc /> /// <summary> /// Processes and encodes a frame into the destination stream /// </summary> /// <param name="frame"> /// A <see cref="VideoFrame" /> instance containing information about the locked frame bitmap or texture /// </param> public override void Feed(VideoFrame frame) { // create sample Sample sample = MediaFactory.CreateSample(); MediaBuffer buffer; switch (frame) { case D3D11VideoFrame d3D11Frame: // Direct3D 11 texture // create media buffer MediaFactory.CreateDXGISurfaceBuffer(typeof(Texture2D).GUID, d3D11Frame.Texture, 0, new RawBool(false), out buffer); // set buffer length using (Buffer2D buffer2D = buffer.QueryInterface <Buffer2D>()) { buffer.CurrentLength = buffer2D.ContiguousLength; } break; case BitmapVideoFrame bmpFrame: // WIC bitmap // create media buffer MediaFactory.CreateWICBitmapBuffer(typeof(Bitmap).GUID, bmpFrame.Bitmap, out buffer); // calculate buffer length buffer.CurrentLength = bmpFrame.BitmapLock.Stride * bmpFrame.Height; // copy pixels Utilities.CopyMemory(buffer.Lock(out _, out _), bmpFrame.BitmapLock.Data.DataPointer, buffer.CurrentLength); // unlock bits buffer.Unlock(); break; case GdiBitmapVideoFrame gdiFrame: // GDI-compatible bitmap // create media buffer // create buffer for copying the bitmap data MediaFactory.Create2DMediaBuffer(frame.Width, frame.Height, new FourCC((int)Format.X8R8G8B8), new RawBool(false), out buffer); // calculate buffer length buffer.CurrentLength = gdiFrame.BitmapData.Stride * frame.Height; // copy data Utilities.CopyMemory(buffer.Lock(out _, out _), gdiFrame.BitmapData.Scan0, buffer.CurrentLength); // unlock bits buffer.Unlock(); break; default: throw new NotSupportedException("The supplied frame does not have a supported type"); } // add buffer to sample sample.AddBuffer(buffer); // set up sample timing if (this.lastFrameTime != 0) { sample.SampleTime = frame.PresentTime - this.firstFramePresentTime; sample.SampleDuration = frame.PresentTime - this.lastFrameTime; } else { // set first frame present time so that we can set the timestamp of subsequent frames relative to the // beggining of the video this.firstFramePresentTime = frame.PresentTime; } this.lastFrameTime = frame.PresentTime; try { this.sinkWriter.WriteSample(this.streamIdx, sample); } finally { buffer.Dispose(); sample.Dispose(); } }