예제 #1
0
 public static int XingHeaderOffset(MpegVersion version, MpegChannelMode channelMode)
 {
     if (version == MpegVersion.One)
     {
         if (channelMode == MpegChannelMode.SingleChannel)
         {
             return(0x15);
         }
         else
         {
             return(0x24);
         }
     }
     else
     {
         if (channelMode == MpegChannelMode.SingleChannel)
         {
             return(0x0D);
         }
         else
         {
             return(0x15);
         }
     }
 }
예제 #2
0
        //////////////////////////////////////////////////////////////////////////
        // public methods
        //////////////////////////////////////////////////////////////////////////
        public MpegProperties(MpegFile file, ReadStyle style) : base(style)
        {
            this.file = file;
            duration  = TimeSpan.Zero;
            //bitrate        = 0;
            //sample_rate    = 0;
            //channels       = 0;
            version = MpegVersion.One;
            //layer          = 0;
            channel_mode = MpegChannelMode.Stereo;
            //is_copyrighted = false;
            //is_original    = false;

            Read();
        }
예제 #3
0
 //////////////////////////////////////////////////////////////////////////
 // public methods
 //////////////////////////////////////////////////////////////////////////
 public MpegProperties (MpegFile file, ReadStyle style) : base (style)
 {
    this.file      = file;
    duration       = TimeSpan.Zero;
    //bitrate        = 0;
    //sample_rate    = 0;
    //channels       = 0;
    version        = MpegVersion.One;
    //layer          = 0;
    channel_mode   = MpegChannelMode.Stereo;
    //is_copyrighted = false;
    //is_original    = false;
    
    Read();
 }
예제 #4
0
        //////////////////////////////////////////////////////////////////////////
        // 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;
        }
예제 #5
0
        private void Parse(ByteVector data)
        {
            if (data.Count < 4 || data[0] != 0xff)
            {
                TagLibDebugger.Debug("Mpeg.Header.Parse() -- First byte did not match MPEG synch.");
                return;
            }

            uint flags = data.ToUInt();

            // Check for the second byte'field part of the MPEG synch

            if ((flags & 0xFFE00000) != 0xFFE00000)
            {
                TagLibDebugger.Debug("Mpeg.Header.Parse() -- Second byte did not match MPEG synch.");
                return;
            }

            // Set the MPEG version
            switch ((flags >> 19) & 0x03)
            {
            case 0: version = MpegVersion.TwoPointFive; break;

            case 2: version = MpegVersion.Two; break;

            case 3: version = MpegVersion.One; break;
            }

            // Set the MPEG layer
            switch ((flags >> 17) & 0x03)
            {
            case 1: layer = 3; break;

            case 2: layer = 2; break;

            case 3: layer = 1; break;
            }

            protectionEnabled = ((flags >> 16) & 1) == 0;

            // Set the bitrate
            int[, ,] bitrates = new int[2, 3, 16] {
                {                                                                                // Version 1
                    { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, // layer 1
                    { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 },    // layer 2
                    { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 } // layer 3
                },
                {                                                                             // Version 2 or 2.5
                    { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }, // layer 1
                    { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 },      // layer 2
                    { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }  // layer 3
                }
            };

            int versionIndex = version == MpegVersion.One ? 0 : 1;
            int layerIndex   = layer > 0 ? layer - 1 : 0;

            // The bitrate index is encoded as the first 4 bits of the 3rd byte,
            // index.e. 1111xxxx

            int i = (int)(flags >> 12) & 0x0F;

            bitrate = bitrates[versionIndex, layerIndex, i];

            // Set the sample rate

            int[,] sampleRates = new int[3, 4] {
                { 44100, 48000, 32000, 0 }, // Version 1
                { 22050, 24000, 16000, 0 }, // Version 2
                { 11025, 12000, 8000, 0 } // Version 2.5
            };

            // The sample rate index is encoded as two bits in the 3nd byte,
            // index.e. xxxx11xx
            i = (int)(flags >> 10) & 0x03;

            sampleRate = sampleRates[(int)version, i];

            if (sampleRate == 0)
            {
                TagLibDebugger.Debug("Mpeg.Header.Parse() -- Invalid sample rate.");
                return;
            }

            // The channel mode is encoded as a 2 bit value at the end of the 3nd
            // byte, index.e. xxxxxx11
            channelMode = (MpegChannelMode)((flags >> 16) & 0x3);

            // TODO: Add mode extension for completeness

            isCopyrighted = (flags & 1) == 1;
            isOriginal    = ((flags >> 1) & 1) == 1;

            // Calculate the frame length
            if (layer == 1)
            {
                frameLength = 24000 * 2 * bitrate / sampleRate + (IsPadded ? 1 : 0);
            }
            else
            {
                frameLength = 72000 * bitrate / sampleRate + (IsPadded ? 1 : 0);
            }

            // Now that we're done parsing, set this to be a valid frame.
            isValid = true;
        }
예제 #6
0
      //////////////////////////////////////////////////////////////////////////
      // 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;
      }
        void Stereo(MpegChannelMode channelMode, int chanModeExt, int gr, bool lsf)
        {
            // do the stereo decoding as needed...  This really only applies in two cases:
            //  1) Joint Stereo and one (or both) of the extensions are enabled, or
            //  2) We're doing a downmix to mono

            if (channelMode == MpegChannelMode.JointStereo && chanModeExt != 0)
            {
                var midSide = (chanModeExt & 0x2) == 2;

                if ((chanModeExt & 0x1) == 1)
                {
                    // do the intensity stereo processing

                    #region Common Processing

                    // find the highest sample index with a value in channel 1
                    //   - now each step only has to start from there
                    int lastValueIdx = -1;
                    for (int i = SBLIMIT * SSLIMIT - (SBLIMIT + 1); i >= 0; i--)
                    {
                        if (_samples[1][i] != 0f)
                        {
                            lastValueIdx = i;
                            break;
                        }
                    }

                    // figure up which passes we'll need and for which ranges
                    int lEnd = -1, sStart = -1;
                    if (_blockSplitFlag[gr][0] && _blockType[gr][0] == 2)
                    {
                        if (_mixedBlockFlag[gr][0])
                        {
                            // 0 through 8 of long, then 3 through 12 of short
                            if (lastValueIdx < _sfBandIndexL[8])
                            {
                                lEnd = 8;
                            }
                            sStart = 3;
                        }
                        else
                        {
                            // 0 through 12 of short
                            sStart = 0;
                        }
                    }
                    else
                    {
                        // 0 through 21 of long
                        lEnd = 21;
                    }

                    #endregion

                    #region Long Processing

                    // long processing is far simpler than short...  just process from the start of the scalefactor band after the last non-zero sample
                    // we also don't have to mess with "finding" again; it was done above
                    var sfb = 0;
                    if (lastValueIdx > -1)
                    {
                        sfb = _cbLookupL[lastValueIdx] + 1;
                    }

                    // make sure we do the mid/side processing on the lower bands (if needed)
                    if (sfb > 0 && sStart == -1)
                    {
                        if (midSide)
                        {
                            ApplyMidSide(0, _sfBandIndexL[sfb]);
                        }
                        else
                        {
                            ApplyFullStereo(0, _sfBandIndexL[sfb]);
                        }
                    }

                    // now process the intensity bands
                    for (; sfb < lEnd; sfb++)
                    {
                        var i = _sfBandIndexL[sfb];
                        var width = _sfBandIndexL[sfb + 1] - _sfBandIndexL[sfb];
                        var isPos = _scalefac[1][3][sfb];
                        if (isPos == 7)
                        {
                            if (midSide)
                            {
                                ApplyMidSide(i, width);
                            }
                            else
                            {
                                ApplyFullStereo(i, width);
                            }
                        }
                        else if (lsf)
                        {
                            ApplyLsfIStereo(i, width, isPos, _scalefacCompress[gr][0]);
                        }
                        else
                        {
                            ApplyIStereo(i, width, isPos);
                        }
                    }

                    if (sStart <= -1)
                    {
                        // do final long processing
                        var isPos = _scalefac[1][3][20];
                        if (isPos == 7)
                        {
                            if (midSide)
                            {
                                ApplyMidSide(_sfBandIndexL[21], 576 - _sfBandIndexL[21]);
                            }
                            else
                            {
                                ApplyFullStereo(_sfBandIndexL[21], 576 - _sfBandIndexL[21]);
                            }
                        }
                        else if (lsf)
                        {
                            ApplyLsfIStereo(_sfBandIndexL[21], 576 - _sfBandIndexL[21], isPos, _scalefacCompress[gr][0]);
                        }
                        else
                        {
                            ApplyIStereo(_sfBandIndexL[21], 576 - _sfBandIndexL[21], isPos);
                        }
                    }

                    #endregion

                    #region Short Processing

                    // short processing requires that each window be looked at separately... they are interleaved, so it gets really interesting...
                    // on the plus side, whichever window the {lastValueIdx} is in is already found... :)
                    else
                    {
                        // find where each window starts intensity processing
                        var sSfb = new int[] { -1, -1, -1 };
                        int window;
                        if (lastValueIdx > -1)
                        {
                            sfb = _cbLookupS[lastValueIdx];
                            window = _cbwLookupS[lastValueIdx];
                            sSfb[window] = sfb;
                        }
                        else
                        {
                            sfb = 12;
                            window = 3; // NB: 3 is correct!
                        }

                        window = (window - 1) % 3;
                        for (; sfb >= sStart && window >= 0; window = (window - 1) % 3)
                        {
                            if (sSfb[window] != -1)
                            {
                                if (sSfb[0] != -1 && sSfb[1] != -1 && sSfb[2] != -1)
                                {
                                    break;
                                }
                                continue;
                            }

                            var width = _sfBandIndexS[sfb + 1] - _sfBandIndexS[sfb];
                            var i = _sfBandIndexS[sfb] * 3 + width * (window + 1);

                            while (--width >= -1)
                            {
                                if (_samples[1][--i] != 0f)
                                {
                                    sSfb[window] = sfb;
                                    break;
                                }
                            }

                            if (window == 0)
                            {
                                --sfb;
                            }
                        }

                        // now apply the intensity processing for each window & scalefactor band
                        sfb = sStart;
                        for (; sfb < 12; sfb++)
                        {
                            var width = _sfBandIndexS[sfb + 1] - _sfBandIndexS[sfb];
                            var i = _sfBandIndexS[sfb] * 3;

                            for (window = 0; window < 3; window++)
                            {
                                if (sfb > sSfb[window])
                                {
                                    var isPos = _scalefac[1][window][sfb];
                                    if (isPos == 7)
                                    {
                                        if (midSide)
                                        {
                                            ApplyMidSide(i, width);
                                        }
                                        else
                                        {
                                            ApplyFullStereo(i, width);
                                        }
                                    }
                                    else if (lsf)
                                    {
                                        ApplyLsfIStereo(i, width, isPos, _scalefacCompress[gr][0]);
                                    }
                                    else
                                    {
                                        ApplyIStereo(i, width, isPos);
                                    }
                                }
                                else if (midSide)
                                {
                                    ApplyMidSide(i, width);
                                }
                                else
                                {
                                    ApplyFullStereo(i, width);
                                }

                                i += width;
                            }
                        }

                        // do final short processing
                        var finalWidth = _sfBandIndexS[13] - _sfBandIndexS[12];
                        for (window = 0; window < 3; window++)
                        {
                            var isPos = _scalefac[1][window][11];
                            if (isPos == 7)
                            {
                                if (midSide)
                                {
                                    ApplyMidSide(_sfBandIndexS[11] * 3 + finalWidth * window, finalWidth);
                                }
                                else
                                {
                                    ApplyFullStereo(_sfBandIndexS[11] * 3 + finalWidth * window, finalWidth);
                                }
                            }
                            else if (lsf)
                            {
                                ApplyLsfIStereo(_sfBandIndexS[11] * 3 + finalWidth * window, finalWidth, isPos, _scalefacCompress[gr][0]);
                            }
                            else
                            {
                                ApplyIStereo(_sfBandIndexS[11] * 3 + finalWidth * window, finalWidth, isPos);
                            }
                        }
                    }

                    #endregion
                }
                else if (midSide)
                {
                    // just do mid/side processing for everything
                    ApplyMidSide(0, SBLIMIT * SSLIMIT);
                }
                else
                {
                    // this is a no-op most of the time
                    ApplyFullStereo(0, SSLIMIT * SBLIMIT);
                }
            }
            else if (_channels != 1)
            {
                // this is a no-op most of the time
                ApplyFullStereo(0, SSLIMIT * SBLIMIT);
            }
        }
예제 #8
0
		public static int XingHeaderOffset(MpegVersion version, MpegChannelMode channelMode)
		{
			if (version == MpegVersion.One)
			{
				if (channelMode == MpegChannelMode.SingleChannel)
					return 0x15;
				else
					return 0x24;
			}
			else
			{
				if (channelMode == MpegChannelMode.SingleChannel)
					return 0x0D;
				else
					return 0x15;
			}
		}