示例#1
0
        public AudioInfo ReadAudioInfo(Stream stream)
        {
            Contract.Ensures(Contract.Result <AudioInfo>() != null);

            var mp4 = new Mp4(stream);

            uint dataSize = mp4.GetChildAtomInfo().Single(atom => atom.FourCC == "mdat").Size;

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

            uint 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.SampleRate > 0)
            {
                return(new AudioInfo(string.Format(CultureInfo.CurrentCulture, "{0}kbps MPEG 4 AAC",
                                                   esds.AverageBitrate > 0
                        ? (int)esds.AverageBitrate / 1000
                        : CalculateBitRate(dataSize, sampleCount, esds.SampleRate)), esds.Channels, 0,
                                     (int)esds.SampleRate, sampleCount));
            }

            // Apple Lossless files have their own atom for storing audio info:
            mp4.DescendToAtom("moov", "trak", "mdia", "minf", "stbl", "stsd", "alac");
            var alac = new AlacAtom(mp4.ReadAtom(mp4.CurrentAtom));

            return(new AudioInfo("Apple Lossless", alac.Channels, alac.BitsPerSample, (int)alac.SampleRate,
                                 sampleCount));
        }
示例#2
0
        internal AtomToMetadataAdapter(Mp4 mp4, AtomInfo[] atoms)
        {
            Contract.Requires(mp4 != null);
            Contract.Requires(atoms != null);

            foreach (AtomInfo atom in atoms)
            {
                byte[] atomData = mp4.ReadAtom(atom);

                switch (atom.FourCC)
                {
                case "trkn":
                    var trackNumberAtom = new TrackNumberAtom(atomData);
                    Add("TrackNumber", trackNumberAtom.TrackNumber.ToString(CultureInfo.InvariantCulture));
                    if (trackNumberAtom.TrackCount > 0)
                    {
                        Add("TrackCount", trackNumberAtom.TrackCount.ToString(CultureInfo.InvariantCulture));
                    }
                    break;

                case "©day":
                    // The ©day atom may contain a full date, or only the year:
                    var      dayAtom = new TextAtom(atomData);
                    DateTime result;
                    if (DateTime.TryParse(dayAtom.Value, CultureInfo.CurrentCulture, DateTimeStyles.NoCurrentDateDefault, out result) && result.Year >= 1000)
                    {
                        base["Day"]   = result.Day.ToString(CultureInfo.InvariantCulture);
                        base["Month"] = result.Month.ToString(CultureInfo.InvariantCulture);
                        base["Year"]  = result.Year.ToString(CultureInfo.InvariantCulture);
                    }
                    else
                    {
                        base["Year"] = dayAtom.Value;
                    }
                    break;

                case "covr":
                    try
                    {
                        CoverArt = new CoverArt(new CovrAtom(atomData).Value);
                    }
                    catch (UnsupportedCoverArtException)
                    { }
                    break;

                default:
                    string mappedKey;
                    if (_map.TryGetValue(atom.FourCC, out mappedKey))
                    {
                        base[mappedKey] = new TextAtom(atomData).Value;
                    }
                    break;
                }
            }
        }
示例#3
0
        static byte[] GenerateIlst(Mp4 originalMp4, MetadataDictionary metadata, SettingsDictionary settings)
        {
            Contract.Requires(originalMp4 != null);
            Contract.Requires(metadata != null);
            Contract.Requires(settings != null);
            Contract.Ensures(Contract.Result <byte[]>() != null);

            using (var resultStream = new MemoryStream())
            {
                var adaptedMetadata = new MetadataToAtomAdapter(metadata, settings);

                // "Reverse DNS" atoms may need to be preserved:
                foreach (ReverseDnsAtom reverseDnsAtom in
                         from listAtom in originalMp4.GetChildAtomInfo()
                         where listAtom.FourCC == "----"
                         select new ReverseDnsAtom(originalMp4.ReadAtom(listAtom)))
                {
                    switch (reverseDnsAtom.Name)
                    {
                    // Always preserve the iTunSMPB (gapless playback) atom:
                    case "iTunSMPB":
                        resultStream.Write(reverseDnsAtom.GetBytes(), 0, reverseDnsAtom.GetBytes().Length);
                        break;

                    // Preserve the existing iTunNORM atom if a new one isn't provided, and AddSoundCheck isn't explicitly False:
                    case "iTunNORM":
                        if (!adaptedMetadata.IncludesSoundCheck &&
                            string.Compare(settings["AddSoundCheck"], bool.FalseString,
                                           StringComparison.OrdinalIgnoreCase) != 0)
                        {
                            resultStream.Write(reverseDnsAtom.GetBytes(), 0, reverseDnsAtom.GetBytes().Length);
                        }
                        break;
                    }
                }

                byte[] atomData = adaptedMetadata.GetBytes();
                resultStream.Write(atomData, 0, atomData.Length);

                return(resultStream.ToArray());
            }
        }