/** Now, this is a bit complicated. Once you understand the follwing code, you will
         * understand the Tao of SkypeKit video transport.
         */
        internal bool GetFrame()
        {
            // At this point, we already have fresh control struct in our memory.
            // This is because we have just called IsNewFrameAvailable and that
            // used GetControlData() to fetch in new data.

            // The following will deterime, which buffer is available for reading,
            // and write the new states back into the control struct. The struct
            // will not be sent back to the shared memory until the end of this method.

            int bufferState = (controlStruct.bufferstates & 0x03);
            if (!haveFrame & bufferState == 0x01) { return false; }
            if (!haveFrame) haveFrame = true;
            if (bufferState == 0x00) controlStruct.bufferstates |= 0x02;
            if (bufferState == 0x03) controlStruct.bufferstates &= ~0x02;
            bufferState = (controlStruct.bufferstates & 0x03);

            // Now we map ourselves to either buffer1 or buffer2
            FrameChannelStruct buffer;
            SharedMemoryChannel channel;
            if (bufferState == 0x1)
            {
                buffer = controlStruct.buffer1;
                channel = frameChannel1;
            }
            else if (bufferState == 0x2)
            {
                buffer = controlStruct.buffer2;
                channel = frameChannel2;
            }
            else throw new Exception("Error: unexpected video control buffer state");

            // If there was no frame buffer channel opened for this buffer, we open it.
            if (channel == null)
            {
                channel = new SharedMemoryChannel();
                bool success = channel.OpenMapping(buffer.bufid);
                if (!success) throw new Exception("Unable to map frame bitmap channel.");
            };

            // If there was an open channel, we check if the IDs match
            if (channel != null)
            {
                if (channel.key != buffer.bufid)
                {
                    return false;
                    //throw new Exception("Error: video control buffer ID and frame buffer ID mismatch");
                };
            };

            // Calculating the video frame size
            width = buffer.width;
            height = buffer.height;
            int bytesPerPixel = buffer.bitsperpixel >> 3;
            int newFrameSize = width * height * bytesPerPixel;

            // If it mismatches with our previous frame size, we need to reallocate buffers.
            if (newFrameSize != bitmapDataSize)
            {
                bitmapData = null;
                bitmapDataSize = newFrameSize;
                bitmapData = new byte[bitmapDataSize];
            }

            // And now we marshal the frame into our bitmapData
            Marshal.Copy(channel.data, bitmapData, 0, bitmapDataSize);

            if (bufferState == 0x1)
            {
                controlStruct.buffer1 = buffer;
                frameChannel1 = channel;
            }
            else if (bufferState == 0x2)
            {
                controlStruct.buffer2 = buffer;
                frameChannel2 = channel;
            }

            // And finally, sending the modified control struct back to the shared memory.
            // Remember - we modified the buffer states at the behinning of this method.
            // We now need to let the other side know that we have finished with current
            // buffer and are basically ready for the next one.
            SendControlData();
            return true;
        }
        public FrameTransport()
        {
            sharedInfoSize = (uint)Marshal.SizeOf((Type)typeof(ControlChannelStruct));

            haveFrame = false;

            bitmapData = null;
            bitmapDataSize = 0;

            frameChannel1 = null;
            frameChannel2 = null;

            controlStruct = new ControlChannelStruct();
            controlStruct.bufferstates = 1;
            controlStruct.buffer1.bufid = -1;
            controlStruct.buffer2.bufid = -1;
            controlStruct.buffer1.clientpointer = 1;
            controlStruct.buffer2.clientpointer = 2;
            controlStruct.fourcccount = 0;
            controlStruct.buftype = BufferType.WinBuffers;

            // Mapping the control channel
            controlChannel = new SharedMemoryChannel();
            bool success = controlChannel.CreateMapping(sharedInfoSize);
            if (!success) throw new Exception("Unable to create memory mapping for video frame transport");

            // Opening the control channel for read-write
            controlChannel.OpenMapping(controlChannel.key);
            int error = Win32.GetLastError();
            if (error != 0) throw new Exception("Unable to map memory for video frame transport");
        }