Ejemplo n.º 1
0
        private static void ParsePicture(Stream fs, ref FlacInfo info)
        {
            var pictureType       = fs.BEInt32();
            var mimeStringLength  = (int)fs.BEInt32();
            var mimeType          = Encoding.ASCII.GetString(fs.ReadBytes(mimeStringLength), 0, mimeStringLength);
            var descriptionLength = (int)fs.BEInt32();
            var description       = Encoding.UTF8.GetString(fs.ReadBytes(descriptionLength), 0, descriptionLength);
            var pictureWidth      = fs.BEInt32();
            var pictureHeight     = fs.BEInt32();
            var colorDepth        = fs.BEInt32();
            var indexedColorCount = fs.BEInt32();
            var pictureDataLength = fs.BEInt32();

            fs.Seek(pictureDataLength, SeekOrigin.Current);
            info.TrueLength -= pictureDataLength;
            info.HasCover    = true;
            if (pictureType > 20)
            {
                pictureType = 21;
            }
            OnLog?.Invoke($" | picture type: {PictureTypeName[pictureType]}");
            OnLog?.Invoke($" | picture format type: {mimeType}");
            if (descriptionLength > 0)
            {
                OnLog?.Invoke($" | description: {description}");
            }
            OnLog?.Invoke($" | attribute: {pictureWidth}px*{pictureHeight}px@{colorDepth}-bit");
            if (indexedColorCount != 0)
            {
                OnLog?.Invoke($" | indexed-color color: {indexedColorCount}");
            }
        }
Ejemplo n.º 2
0
        private static void ParseStreamInfo(Stream fs, ref FlacInfo info)
        {
            var minBlockSize = fs.BEInt16();
            var maxBlockSize = fs.BEInt16();
            var minFrameSize = fs.BEInt24();
            var maxFrameSize = fs.BEInt24();
            var buffer       = fs.ReadBytes(8);
            var br           = new BitReader(buffer);
            var sampleRate   = br.GetBits(20);
            var channelCount = br.GetBits(3) + 1;
            var bitPerSample = br.GetBits(5) + 1;
            var totalSample  = br.GetBits(36);
            var md5          = fs.ReadBytes(16);

            info.RawLength = channelCount * bitPerSample / 8 * totalSample;
            OnLog?.Invoke($" | minimum block size: {minBlockSize}, maximum block size: {maxBlockSize}");
            OnLog?.Invoke($" | minimum frame size: {minFrameSize}, maximum frame size: {maxFrameSize}");
            OnLog?.Invoke($" | Sample rate: {sampleRate}Hz, bits per sample: {bitPerSample}-bit");
            OnLog?.Invoke($" | Channel count: {channelCount}");
            var md5String = md5.Aggregate(string.Empty, (current, item) => current + $"{item:X2}");

            OnLog?.Invoke($" | MD5: {md5String}");
        }
Ejemplo n.º 3
0
        private static void ParseVorbisComment(Stream fs, ref FlacInfo info)
        {
            // only here in flac use little-endian
            var vendorLength        = (int)fs.LEInt32();
            var vendorRawStringData = fs.ReadBytes(vendorLength);
            var vendor = Encoding.UTF8.GetString(vendorRawStringData, 0, vendorLength);

            info.Encoder = vendor;
            OnLog?.Invoke($" | Vendor: {vendor}");
            var userCommentListLength = fs.LEInt32();

            for (var i = 0; i < userCommentListLength; ++i)
            {
                var commentLength        = (int)fs.LEInt32();
                var commentRawStringData = fs.ReadBytes(commentLength);
                var comment       = Encoding.UTF8.GetString(commentRawStringData, 0, commentLength);
                var splitterIndex = comment.IndexOf('=');
                var key           = comment.Substring(0, splitterIndex);
                var value         = comment.Substring(splitterIndex + 1, comment.Length - 1 - splitterIndex);
                info.VorbisComment[key] = value;
                var summary = value.Length > 25 ? value.Substring(0, 25) + "..." : value;
                OnLog?.Invoke($" | [{key}] = '{summary.Replace('\n', ' ')}'");
            }
        }
Ejemplo n.º 4
0
        public static FlacInfo GetMetadataFromFlac(string flacPath)
        {
            using (var fs = File.Open(flacPath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                if (fs.Length < SizeThreshold)
                {
                    return(new FlacInfo());
                }
                var info = new FlacInfo {
                    TrueLength = fs.Length
                };
                var header = Encoding.ASCII.GetString(fs.ReadBytes(4), 0, 4);
                if (header != "fLaC")
                {
                    throw new InvalidDataException($"Except an flac but get an {header}");
                }

                // METADATA_BLOCK_HEADER
                // 1-bit Last-metadata-block flag
                // 7-bit BLOCK_TYPE
                // 24-bit Length
                while (fs.Position < fs.Length)
                {
                    var blockHeader       = fs.BEInt32();
                    var lastMetadataBlock = blockHeader >> 31 == 0x1;
                    var blockType         = (BlockType)((blockHeader >> 24) & 0x7f);
                    var length            = blockHeader & 0xffffff;
                    info.TrueLength -= length;
                    OnLog?.Invoke($"|+{blockType} with Length: {length}");
                    switch (blockType)
                    {
                    case BlockType.STREAMINFO:
                        Debug.Assert(length == 34, "Stream info block length must be 34");
                        ParseStreamInfo(fs, ref info);
                        break;

                    case BlockType.VORBIS_COMMENT:
                        ParseVorbisComment(fs, ref info);
                        break;

                    case BlockType.PICTURE:
                        ParsePicture(fs, ref info);
                        break;

                    case BlockType.PADDING:
                    case BlockType.APPLICATION:
                    case BlockType.SEEKTABLE:
                    case BlockType.CUESHEET:
                        fs.Seek(length, SeekOrigin.Current);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException($"Invalid BLOCK_TYPE: 0x{blockType:X2}");
                    }
                    if (lastMetadataBlock)
                    {
                        break;
                    }
                }
                return(info);
            }
        }