//////////////////////////////////////////////////////////////////////////
        // private methods
        //////////////////////////////////////////////////////////////////////////

        private void Read()
        {
            // Since we've likely just looked for the ID3v1 tag, start at the end of the
            // file where we're least likely to have to have to move the disk head.

            long last = file.LastFrameOffset;

            if (last < 0)
            {
                TagLibDebugger.Debug("Mpeg.Properties.Read() -- Could not find a valid last MPEG frame in the stream.");
                return;
            }

            file.Seek(last);
            MpegHeader last_header = new MpegHeader(file.ReadBlock(4));

            long first = file.FirstFrameOffset;

            if (first < 0)
            {
                TagLibDebugger.Debug("Mpeg.Properties.Read() -- Could not find a valid first MPEG frame in the stream.");
                return;
            }

            if (!last_header.IsValid)
            {
                long pos = last;

                while (pos > first)
                {
                    pos = file.PreviousFrameOffset(pos);

                    if (pos < 0)
                    {
                        break;
                    }

                    file.Seek(pos);
                    MpegHeader header = new MpegHeader(file.ReadBlock(4));

                    if (header.IsValid)
                    {
                        last_header = header;
                        last        = pos;
                        break;
                    }
                }
            }

            // Now jump back to the front of the file and read what we need from there.

            file.Seek(first);
            MpegHeader first_header = new MpegHeader(file.ReadBlock(4));

            if (!first_header.IsValid || !last_header.IsValid)
            {
                TagLibDebugger.Debug("Mpeg.Properties.Read() -- Page headers were invalid.");
                return;
            }

            // Check for a Xing header that will help us in gathering information about a
            // VBR stream.

            int xing_header_offset = MpegXingHeader.XingHeaderOffset(first_header.Version,
                                                                     first_header.ChannelMode);

            file.Seek(first + xing_header_offset);
            MpegXingHeader xing_header = new MpegXingHeader(file.ReadBlock(16));

            // Read the length and the bitrate from the Xing header.

            if (xing_header.IsValid && first_header.SampleRate > 0 && xing_header.TotalFrames > 0)
            {
                int [] block_size = { 0, 384, 1152, 1152 };

                double time_per_frame = block_size [first_header.Layer];
                time_per_frame = first_header.SampleRate > 0 ? time_per_frame / first_header.SampleRate : 0;
                duration       = new TimeSpan((int)(time_per_frame * xing_header.TotalFrames) * TimeSpan.TicksPerSecond);
                bitrate        = (int)(duration > TimeSpan.Zero ? ((xing_header.TotalSize * 8L) / duration.TotalSeconds) / 1000 : 0);
            }

            // Since there was no valid Xing header found, we hope that we're in a constant
            // bitrate file.

            // TODO: Make this more robust with audio property detection for VBR without a
            // Xing header.

            else if (first_header.FrameLength > 0 && first_header.Bitrate > 0)
            {
                int frames = (int)((last - first) / first_header.FrameLength + 1);

                duration = TimeSpan.FromSeconds((double)(first_header.FrameLength * frames) / (double)(first_header.Bitrate * 125) + 0.5);
                bitrate  = first_header.Bitrate;
            }


            sample_rate    = first_header.SampleRate;
            channels       = first_header.ChannelMode == MpegChannelMode.SingleChannel ? 1 : 2;
            version        = first_header.Version;
            layer          = first_header.Layer;
            channel_mode   = first_header.ChannelMode;
            is_copyrighted = first_header.IsCopyrighted;
            is_original    = first_header.IsOriginal;
        }