Пример #1
0
        /// <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 (var 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.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;
            }

            sample.SampleTime  = frame.PresentTime - this.firstFramePresentTime;
            this.lastFrameTime = frame.PresentTime;

            try {
                this.sinkWriter.WriteSample(this.streamIdx, sample);
            } catch (SharpDXException) {
                buffer.Dispose();
                sample.Dispose();
            }
        }
        /// <inheritdoc />
        /// <summary>
        ///   Encodes a single frame and writes the output to the destination stream.
        /// </summary>
        /// <param name="frame">Video frame to be encoded</param>
        /// <exception cref="T:System.InvalidOperationException">A frame has already been fed to the encoder</exception>
        /// <exception cref="T:System.NotSupportedException">The supplied video frame does not have a supported format</exception>
        public override void Feed(VideoFrame frame)
        {
            using (var frameEncode = new BitmapFrameEncode(this.encoder)) {
                frameEncode.Initialize();

                switch (frame)
                {
                case BitmapVideoFrame bmpVideoFrame: // GDI-compatible bitmap (SharpDX.WIC)
                    // already got a WIC bitmap
                    frameEncode.WriteSource(bmpVideoFrame.Bitmap);
                    break;

                case GdiBitmapVideoFrame gdiVideoFrame: // GDI-compatible bitmap (System.Drawing)
                    // construct a WIC bitmap from a GDI-compatible bitmap
                    using (var bmp = new Bitmap(this.factory,
                                                frame.Width,
                                                frame.Height,
                                                PixelFormat.Format32bppBGRA,
                                                new DataRectangle(gdiVideoFrame.BitmapData.Scan0,
                                                                  gdiVideoFrame.BitmapData.Stride))) {
                        frameEncode.WriteSource(bmp);
                    }

                    break;

                case D3D11VideoFrame d3D11VideoFrame: // ID3D11Texture2D
                    try {
                        // map texture to system memory so that we can access the pixel data
                        DataBox box = d3D11VideoFrame.Texture.Device.ImmediateContext.MapSubresource(d3D11VideoFrame.Texture,
                                                                                                     0,
                                                                                                     MapMode.Read,
                                                                                                     MapFlags.None);

                        using (var bmp = new Bitmap(this.factory,
                                                    frame.Width,
                                                    frame.Height,
                                                    PixelFormat.Format32bppBGRA,
                                                    new DataRectangle(box.DataPointer, box.RowPitch))) {
                            frameEncode.WriteSource(bmp);
                        }
                    } finally {
                        // unmap texture from system memory and release related resources
                        using (DeviceContext ctx = d3D11VideoFrame.Texture.Device.ImmediateContext) {
                            ctx.UnmapSubresource(d3D11VideoFrame.Texture, 0);
                            ctx.ClearState();
                            ctx.Flush();
                        }

#if DEBUG
                        // HACK: we are accessing the `Device` property of the Texture2D in order to map the data to system memory.
                        //       Internally, SharpDX gets the Device if not previously accessed. We are releasing the device on the
                        //       Dispose() methods of the video providers but this weak reference stays tracked by SharpDX even
                        //       after its memory has been released
                        ObjectTracker.UnTrack(d3D11VideoFrame.Texture.Device);
#endif
                    }

                    break;
                }

                frameEncode.Commit();
                this.encoder.Commit();
            }
        }