/// <summary>
        /// Processes a NAL.
        /// </summary>
        /// <param name="nal">The NAL to be processed.</param>
        /// <returns>Type of NAL.</returns>
        private int ProcessNal(Nal nal)
        {
            // get the NAL type
            int nalType = -1;

            if (nal.Buffer.Length > 4)
            {
                byte[] header = new byte[5];
                nal.Buffer.CopyTo(0, header, 0, 5);
                nalType = (header[0] == 0 && header[1] == 0 && header[2] == 0 && header[3] == 1) ? (header[4] & 0x1F) : -1;
            }
            //Log.Verbose("NAL: type = {0}, len = {1}", nalType, nal.Buffer.Length);

            // process the first SPS record we encounter
            if (nalType == 7 && !isDecoding)
            {
                byte[] sps = new byte[nal.Buffer.Length];
                nal.Buffer.CopyTo(sps);
                SpsParser parser = new SpsParser(sps, (int)nal.Buffer.Length);
                //Log.Verbose("SPS: {0}x{1} @ {2}", parser.width, parser.height, parser.fps);

                VideoEncodingProperties properties = VideoEncodingProperties.CreateH264();
                properties.ProfileId = H264ProfileIds.High;
                properties.Width     = (uint)parser.width;
                properties.Height    = (uint)parser.height;

                streamSource                  = new MediaStreamSource(new VideoStreamDescriptor(properties));
                streamSource.BufferTime       = TimeSpan.Zero;
                streamSource.CanSeek          = false;
                streamSource.Duration         = TimeSpan.Zero;
                streamSource.SampleRequested += HandleSampleRequested;

                var action = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
                {
                    statusTextBlock.Visibility = Visibility.Collapsed;
                    media.SetMediaStreamSource(streamSource);
                    media.Play();
                    storyboard.Begin();
                });
                isDecoding = true;
            }

            // queue the frame
            if (nalType > 0 && isDecoding)
            {
                if (deferral != null)
                {
                    request.Sample = MediaStreamSample.CreateFromBuffer(nal.Buffer, new TimeSpan(0));
                    lock (availableNals)
                    {
                        //Log.Verbose("availableNals.Enqueue");
                        availableNals.Enqueue(nal);
                    }
                    deferral.Complete();
                    deferral = null;
                    request  = null;
                    //Log.Verbose("Deferral Complete");
                }
                else
                {
                    //Log.Verbose("usedNals.Enqueue");
                    lock (usedNals)
                    {
                        usedNals.Enqueue(nal);
                    }
                }
            }

            // return the NAL type
            return(isDecoding ? nalType : -1);
        }
        /// <summary>
        /// Reads bytes form the socket and parses them into NALs.
        /// </summary>
        /// <returns>The asynchronous task.</returns>
        private async Task ReadSocketAsync()
        {
            Log.Info("+VideoPage.ReadSocketAsync");
            Nal  nal           = availableNals.Dequeue();
            int  numZeroes     = 0;
            int  numReadErrors = 0;
            bool gotHeader     = false;

            // look for a TCP/IP connection
            try
            {
                // try to connect to the device
                socket = new StreamSocket();
                HostName hostName = new HostName(camera.Address);
                CancellationTokenSource tokenSource = new CancellationTokenSource();
                tokenSource.CancelAfter(settings.ScanTimeout);
                await socket.ConnectAsync(hostName, camera.Port.ToString()).AsTask(tokenSource.Token);

                // if we get here, we opened the socket
                isConnected = true;
                DataReader reader = new DataReader(socket.InputStream);
                reader.InputStreamOptions = InputStreamOptions.Partial;

                while (!isCancelled)
                {
                    uint len = await reader.LoadAsync(BUFFER_SIZE);

                    //Log.Verbose("numBytes = {0}", len);
                    if (nal == null)
                    {
                        lock (availableNals)
                        {
                            //Log.Verbose("availableNals.Dequeue: {0}", availableNals.Count);
                            nal = (availableNals.Count > 0) ? availableNals.Dequeue() : null;
                        }
                    }

                    // process the input buffer
                    if (nal == null)
                    {
                        if (len > 0)
                        {
                            reader.ReadBuffer(len);
                        }
                    }
                    else if (len > 0)
                    {
                        numReadErrors = 0;
                        for (int i = 0; i < len && nal != null && !isCancelled; i++)
                        {
                            // resize the NAL if necessary
                            if (nal.Stream.Length == nal.Buffer.Capacity)
                            {
                                nal.Resize(nal.Buffer.Capacity + NAL_SIZE_INC);
                            }

                            // add the byte to the NAL
                            byte b = reader.ReadByte();
                            nal.Stream.WriteByte(b);

                            // look for a header
                            if (b == 0)
                            {
                                numZeroes++;
                            }
                            else
                            {
                                if (b == 1 && numZeroes == 3)
                                {
                                    if (nal.Stream.Length > 4)
                                    {
                                        if (gotHeader)
                                        {
                                            nal.Buffer.Length = (uint)nal.Stream.Length - 4;
                                            int nalType = ProcessNal(nal);
                                            if (isCancelled)
                                            {
                                                break;
                                            }
                                            if (nalType != -1)
                                            {
                                                lock (availableNals)
                                                {
                                                    //Log.Verbose("availableNals.Dequeue: {0}", availableNals.Count);
                                                    nal = (availableNals.Count > 0) ? availableNals.Dequeue() : null;
                                                }
                                            }
                                        }
                                        if (nal != null)
                                        {
                                            nal.Stream.Seek(0, SeekOrigin.Begin);
                                            nal.Stream.SetLength(0);
                                            nal.Stream.WriteByte(0);
                                            nal.Stream.WriteByte(0);
                                            nal.Stream.WriteByte(0);
                                            nal.Stream.WriteByte(1);
                                        }
                                        else
                                        {
                                            //Log.Verbose("null");
                                        }
                                    }
                                    gotHeader = true;
                                }
                                numZeroes = 0;
                            }
                        }
                    }
                    else
                    {
                        numReadErrors++;
                        if (numReadErrors >= MAX_READ_ERRORS)
                        {
                            DisplayStatusMessage(Res.Error.LostConnection);
                            break;
                        }
                    }
                }
                reader.Dispose();
                socket.Dispose();
                isDecoding  = false;
                isConnected = false;
                await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                {
                    media.Stop();
                    Frame.GoBack();
                });
            }
            catch (Exception ex)
            {
                DisplayStatusMessage(isConnected ? Res.Error.LostConnection : Res.Error.CouldntConnect);
                Log.Error("EXCEPTION: {0}", ex.ToString());
                isConnected = false;
                return;
            }
            Log.Info("-VideoPage.ReadSocketAsync");
        }