示例#1
0
        public AudioInfo ReadAudioInfo(Stream stream)
        {
            using (var reader = new FrameReader(stream))
                try
                {
                    var frameHeader = ReadFrameHeader(reader);

                    // Frame count is found in the optional Xing (most common) or VBRI header
                    var optionalHeader = ReadXingHeader(reader, frameHeader);
                    if (optionalHeader.Incomplete)
                    {
                        optionalHeader = ReadVbriHeader(reader);
                    }

                    return(AudioInfo.CreateForLossy(
                               "MP3",
                               frameHeader.Channels,
                               frameHeader.SampleRate,
                               optionalHeader.FrameCount * frameHeader.SamplesPerFrame,
                               DetermineBitRate(frameHeader, optionalHeader)));
                }
                catch (EndOfStreamException e)
                {
                    // If a frame sync couldn't be located, this isn't an MP3
                    throw new AudioInvalidException(e.Message);
                }
        }
示例#2
0
        public void BitRateIsSerialized()
        {
            var formatter = new BinaryFormatter();

            using (var stream = new MemoryStream())
            {
                formatter.Serialize(stream, AudioInfo.CreateForLossy("Test", 2, 44100, 0, 1000));
                stream.Position = 0;

                Assert.Equal(1000, ((AudioInfo)formatter.Deserialize(stream)).BitRate);
            }
        }
示例#3
0
        public AudioInfo ReadAudioInfo(Stream stream)
        {
            try
            {
                var mp4 = new Mp4Model(stream);

                mp4.DescendToAtom("moov", "trak", "mdia", "minf", "stbl", "stts");
                var stts = new SttsAtom(mp4.ReadAtom(mp4.CurrentAtom));

                var sampleCount = stts.PacketCount * stts.PacketSize;

                mp4.DescendToAtom("moov", "trak", "mdia", "minf", "stbl", "stsd", "mp4a", "esds");
                var esds = new EsdsAtom(mp4.ReadAtom(mp4.CurrentAtom));
                if (esds.IsAac)
                {
                    mp4.Reset();
                    return(AudioInfo.CreateForLossy("AAC", esds.Channels, (int)esds.SampleRate, sampleCount,
                                                    CalculateBitRate(mp4.GetChildAtomInfo().Single(atom =>
                                                                                                   atom.FourCc.Equals("mdat", StringComparison.Ordinal)).Size,
                                                                     sampleCount,
                                                                     esds.SampleRate)));
                }

                // Apple Lossless files have their own atom for storing audio info
                if (!mp4.DescendToAtom("moov", "trak", "mdia", "minf", "stbl", "stsd", "alac"))
                {
                    throw new AudioUnsupportedException("Only AAC and ALAC MP4 streams are supported.");
                }

                var alac = new AlacAtom(mp4.ReadAtom(mp4.CurrentAtom));
                return(AudioInfo.CreateForLossless(
                           "ALAC",
                           alac.Channels,
                           alac.BitsPerSample,
                           (int)alac.SampleRate,
                           sampleCount));
            }
            catch (EndOfStreamException e)
            {
                throw new AudioInvalidException(e.Message);
            }
        }
示例#4
0
        public unsafe AudioInfo ReadAudioInfo(Stream stream)
        {
            OggStream?oggStream = null;

            SafeNativeMethods.VorbisCommentInit(out var vorbisComment);
#if NETSTANDARD2_0
            var buffer = ArrayPool <byte> .Shared.Rent(4096);
#else
            Span <byte> buffer = stackalloc byte[4096];
#endif

            try
            {
                using (var sync = new OggSync())
                    using (var decoder = new VorbisDecoder())
                    {
                        OggPage page;

                        do
                        {
                            // Read from the buffer into a page
                            while (!sync.PageOut(out page))
                            {
#if NETSTANDARD2_0
                                var bytesRead = stream.Read(buffer, 0, buffer.Length);
#else
                                var bytesRead = stream.Read(buffer);
#endif
                                if (bytesRead == 0)
                                {
                                    throw new AudioInvalidException("No Ogg stream was found.");
                                }

                                var nativeBuffer = new Span <byte>(sync.Buffer(bytesRead).ToPointer(), bytesRead);
#if NETSTANDARD2_0
                                buffer.AsSpan().Slice(0, bytesRead).CopyTo(nativeBuffer);
#else
                                buffer.Slice(0, bytesRead).CopyTo(nativeBuffer);
#endif
                                sync.Wrote(bytesRead);
                            }

                            oggStream ??= new(SafeNativeMethods.OggPageSerialNo(page));
                            oggStream.PageIn(page);

                            while (oggStream.PacketOut(out var packet))
                            {
                                if (!SafeNativeMethods.VorbisSynthesisIdHeader(packet))
                                {
                                    throw new AudioUnsupportedException("Not a Vorbis stream.");
                                }

                                decoder.HeaderIn(vorbisComment, packet);

                                var info = decoder.GetInfo();
                                return(AudioInfo.CreateForLossy(
                                           "Vorbis",
                                           info.Channels,
#if WINDOWS
                                           info.Rate,
                                           GetFinalGranulePosition(oggStream.SerialNumber, stream),
                                           Math.Max(info.BitRateNominal, 0)));
#else
                                           (int)info.Rate,
                                           GetFinalGranulePosition((int)oggStream.SerialNumber, stream),
                                       Math.Max((int)info.BitRateNominal, 0));
#endif
                            }
                        } while (!SafeNativeMethods.OggPageEos(page));

                        throw new AudioInvalidException("The end of the Ogg stream was reached without finding a header.");
                    }
            }
            finally
            {
#if NETSTANDARD2_0
                ArrayPool <byte> .Shared.Return(buffer);
#endif
                SafeNativeMethods.VorbisCommentClear(ref vorbisComment);
                oggStream?.Dispose();
            }
        }
示例#5
0
 public void BitRateNegativeThrowsException()
 {
     Assert.Throws <AudioInvalidException>(() => AudioInfo.CreateForLossy("Test", 2, 44100, 0, -1));
 }