Exemplo n.º 1
0
        /// <summary>
        /// Copy the frame content to a <xref href="System.Byte"/>[] buffer as a contiguous block of memory
        /// containing the Y, U, and V planes one after another, and the alpha plane at the end if
        /// present.
        /// </summary>
        /// <param name="buffer">The destination buffer to copy the frame to.</param>
        public void CopyTo(byte[] buffer)
        {
            unsafe
            {
                fixed(void *ptr = buffer)
                {
                    // Note : System.Buffer.MemoryCopy() essentially does the same (without stride), but gets transpiled by IL2CPP
                    // into the C++ corresponding to the IL instead of a single memcpy() call. This results in a large overhead,
                    // especially in Debug config where one can lose 5-10 FPS just because of this.
                    void *dst   = ptr;
                    ulong sizeY = (ulong)strideY * height;

                    PeerConnection.MemCpyStride(dst, strideY, (void *)dataY, strideY, (int)width, (int)height);
                    dst = (void *)((ulong)dst + sizeY);
                    ulong sizeU = (ulong)strideU * height / 2;

                    PeerConnection.MemCpyStride(dst, strideU, (void *)dataU, strideU, (int)width / 2, (int)height / 2);
                    dst = (void *)((ulong)dst + sizeU);
                    ulong sizeV = (ulong)strideV * height / 2;

                    PeerConnection.MemCpyStride(dst, strideV, (void *)dataV, strideV, (int)width / 2, (int)height / 2);
                    if (dataA.ToPointer() != null)
                    {
                        dst = (void *)((ulong)dst + sizeV);
                        PeerConnection.MemCpyStride(dst, strideA, (void *)dataA, strideA, (int)width, (int)height);
                    }
                }
            }
        }
        /// <summary>
        /// Try to enqueue a new video frame encoded in raw ARGB format.
        /// If the internal queue reached its maximum capacity, do nothing and drop the frame.
        /// </summary>
        /// <param name="frame">The video frame to enqueue</param>
        /// <returns>Return <c>true</c> if the frame was enqueued successfully, or <c>false</c> if it was dropped</returns>
        /// <remarks>This should only be used if the queue has storage for a compatible video frame encoding.</remarks>
        public bool Enqueue(ARGBVideoFrame frame)
        {
            double curTime = _stopwatch.Elapsed.TotalMilliseconds;

            // Always update queued time, which refers to calling Enqueue(), even
            // if the queue is full and the frame is dropped.
            float queuedDt = (float)(curTime - _lastQueuedTimeMs);

            _lastQueuedTimeMs = curTime;

            // Try to get some storage for that new frame
            ulong byteSize = (ulong)frame.stride * frame.height * 4;
            T     storage  = GetStorageFor(byteSize);

            if (storage == null)
            {
                // Too many frames in queue, drop the current one
                float droppedDt = (float)(curTime - _lastDroppedTimeMs);
                _lastDroppedTimeMs = curTime;
                _droppedFrameTimeAverage.Push(1000f / droppedDt);
                return(false);
            }

            // Copy the new frame to its storage
            unsafe
            {
                fixed(void *dst = storage.Buffer)
                {
                    void *src = (void *)frame.data;

                    PeerConnection.MemCpyStride(dst, frame.stride, (void *)frame.data, frame.stride, (int)frame.width * 4, (int)frame.height);
                }
            }
            storage.Width  = frame.width;
            storage.Height = frame.height;

            // Enqueue for later delivery
            _frameQueue.Enqueue(storage);
            _queuedFrameTimeAverage.Push(1000f / queuedDt);
            _droppedFrameTimeAverage.Push(0f);
            return(true);
        }