private void ClientReceiveFrame(Parsec.ParsecFrame frame, IntPtr image, IntPtr opaque) { // Debug.Log($"Frame received at {Time.time}. Format:{frame.format} Size:{frame.width}x{frame.height} ActualSize:{frame.fullWidth}x{frame.fullHeight} ByteSize:{frame.size}"); decoder.Decode(frame, image); Vector2 padding = new Vector2((float)frame.width / frame.fullWidth, (float)frame.height / frame.fullHeight); parsecGuestView.Populate(decoder.Y, decoder.U, decoder.V, padding, decoder.AspectRatio); }
// TODO: I don't know for certain, but this is probably not the most efficient way of // getting an image to Unity. I'm guessing that ClientPollFrame pulls the texture // from GPU memory (where it was initially decoded) into system memory, before it is // passed here. Then, Unity places it back into GPU memory. public void Decode(Parsec.ParsecFrame frame, System.IntPtr image) { if (frame.format != Parsec.ParsecColorFormat.FORMAT_I420) { throw new System.Exception($"Decoder does not currently support {frame.format}. Only {Parsec.ParsecColorFormat.FORMAT_I420} is permitted."); } // The texture will be built if it does not currently exist. // Otherwise, only rebuild the texture if the dimensions have changed. if (Y == null || (Y.width != frame.fullWidth || Y.height != frame.fullHeight)) { if (Y != null) { Object.Destroy(Y); Object.Destroy(U); Object.Destroy(V); } Y = new Texture2D((int)frame.fullWidth, (int)frame.fullHeight, TextureFormat.R8, false, false); U = new Texture2D((int)frame.fullWidth / 2, (int)frame.fullHeight / 2, TextureFormat.R8, false, false); V = new Texture2D((int)frame.fullWidth / 2, (int)frame.fullHeight / 2, TextureFormat.R8, false, false); } int yBytes = (int)frame.fullWidth * (int)frame.fullHeight; int uvBytes = (int)frame.fullWidth / 2 * (int)frame.fullHeight / 2; Y.LoadRawTextureData(image, yBytes); Y.Apply(); System.IntPtr uPtr = System.IntPtr.Add(image, yBytes); U.LoadRawTextureData(uPtr, uvBytes); U.Apply(); System.IntPtr vPtr = System.IntPtr.Add(uPtr, uvBytes); V.LoadRawTextureData(vPtr, ((int)frame.fullWidth * (int)frame.fullHeight) / 2); V.Apply(); Padding = new Vector2((float)frame.width / frame.fullWidth, (float)frame.height / frame.fullHeight); AspectRatio = (float)frame.width / (float)frame.height; }
private void OnClientReceiveFrame(Parsec.ParsecFrame frame, IntPtr image, IntPtr opaque) { parsecFrameDecoder.Decode(frame, image); // TODO: Could just initialize the guest view with the decoder? parsecGuestView.Populate(parsecFrameDecoder.Y, parsecFrameDecoder.U, parsecFrameDecoder.V, parsecFrameDecoder.Padding, parsecFrameDecoder.AspectRatio); }