/// <summary>
        ///    Parses boxes for a specified range, looking for tags.
        /// </summary>
        /// <param name="start">
        ///    A <see cref="long" /> value specifying the seek position
        ///    at which to start reading.
        /// </param>
        /// <param name="end">
        ///    A <see cref="long" /> value specifying the seek position
        ///    at which to stop reading.
        /// </param>
        private void ParseTag(long start, long end,
                              List <BoxHeader> parents)
        {
            BoxHeader header;

            for (long position = start; position < end;
                 position += header.TotalBoxSize)
            {
                header = new BoxHeader(file, position);

                if (header.BoxType == BoxType.Moov)
                {
                    ParseTag(header.HeaderSize + position,
                             header.TotalBoxSize + position,
                             AddParent(parents, header));
                }
                else if (header.BoxType == BoxType.Mdia ||
                         header.BoxType == BoxType.Minf ||
                         header.BoxType == BoxType.Stbl ||
                         header.BoxType == BoxType.Trak)
                {
                    ParseTag(header.HeaderSize + position,
                             header.TotalBoxSize + position,
                             AddParent(parents, header));
                }
                else if (header.BoxType == BoxType.Udta)
                {
                    IsoUserDataBox udtaBox = BoxFactory.CreateBox(file,
                                                                  header) as IsoUserDataBox;

                    // Since we can have multiple udta boxes, save the parent for each one
                    List <BoxHeader> new_parents = AddParent(
                        parents, header);
                    udtaBox.ParentTree = new_parents.ToArray();

                    udta_boxes.Add(udtaBox);
                }
                else if (header.BoxType == BoxType.Mdat)
                {
                    mdat_start = position;
                    mdat_end   = position + header.TotalBoxSize;
                }

                if (header.TotalBoxSize == 0)
                {
                    break;
                }
            }
        }
示例#2
0
        /// <summary>
        ///    Gets a tag of a specified type from the current instance,
        ///    optionally creating a new tag if possible.
        /// </summary>
        /// <param name="type">
        ///    A <see cref="TagLib.TagTypes" /> value indicating the
        ///    type of tag to read.
        /// </param>
        /// <param name="create">
        ///    A <see cref="bool" /> value specifying whether or not to
        ///    try and create the tag if one is not found.
        /// </param>
        /// <returns>
        ///    A <see cref="Tag" /> object containing the tag that was
        ///    found in or added to the current instance. If no
        ///    matching tag was found and none was created, <see
        ///    langword="null" /> is returned.
        /// </returns>
        /// <remarks>
        ///    At the time of this writing, only <see cref="AppleTag" />
        ///    is supported. All other tag types will be ignored.
        /// </remarks>
        public override TagLib.Tag GetTag(TagTypes type, bool create)
        {
            if (type == TagTypes.Apple)
            {
                if (apple_tag == null && create)
                {
                    IsoUserDataBox udtaBox = FindAppleTagUdta();
                    if (null == udtaBox)
                    {
                        udtaBox = new IsoUserDataBox();
                    }
                    apple_tag = new AppleTag(udtaBox);
                    tag.SetTags(apple_tag);
                }

                return(apple_tag);
            }

            return(null);
        }
        /// <summary>
        ///    Parses boxes for a specified range, looking for tags and
        ///    properties.
        /// </summary>
        /// <param name="start">
        ///    A <see cref="long" /> value specifying the seek position
        ///    at which to start reading.
        /// </param>
        /// <param name="end">
        ///    A <see cref="long" /> value specifying the seek position
        ///    at which to stop reading.
        /// </param>
        /// <param name="handler">
        ///    A <see cref="IsoHandlerBox" /> object that applied to the
        ///    range being searched.
        /// </param>
        private void ParseTagAndProperties(long start, long end,
                                           IsoHandlerBox handler, List <BoxHeader> parents)
        {
            BoxHeader header;

            for (long position = start; position < end;
                 position += header.TotalBoxSize)
            {
                header = new BoxHeader(file, position);
                ByteVector type = header.BoxType;

                if (type == BoxType.Moov)
                {
                    ParseTagAndProperties(header.HeaderSize + position,
                                          header.TotalBoxSize + position,
                                          handler,
                                          AddParent(parents, header));
                }
                else if (type == BoxType.Mdia ||
                         type == BoxType.Minf ||
                         type == BoxType.Stbl ||
                         type == BoxType.Trak)
                {
                    ParseTagAndProperties(
                        header.HeaderSize + position,
                        header.TotalBoxSize + position,
                        handler,
                        AddParent(parents, header));
                }
                else if (type == BoxType.Stsd)
                {
                    stsd_boxes.Add(BoxFactory.CreateBox(
                                       file, header, handler));
                }
                else if (type == BoxType.Hdlr)
                {
                    handler = BoxFactory.CreateBox(file,
                                                   header, handler) as
                              IsoHandlerBox;
                }
                else if (mvhd_box == null &&
                         type == BoxType.Mvhd)
                {
                    mvhd_box = BoxFactory.CreateBox(file,
                                                    header, handler) as
                               IsoMovieHeaderBox;
                }
                else if (type == BoxType.Udta)
                {
                    IsoUserDataBox udtaBox = BoxFactory.CreateBox(file,
                                                                  header, handler) as
                                             IsoUserDataBox;

                    // Since we can have multiple udta boxes, save the parent for each one
                    List <BoxHeader> new_parents = AddParent(
                        parents, header);
                    udtaBox.ParentTree = new_parents.ToArray();

                    udta_boxes.Add(udtaBox);
                }
                else if (type == BoxType.Mdat)
                {
                    mdat_start = position;
                    mdat_end   = position + header.TotalBoxSize;
                }

                if (header.TotalBoxSize == 0)
                {
                    break;
                }
            }
        }
示例#4
0
        /// <summary>
        ///    Reads the file with a specified read style.
        /// </summary>
        /// <param name="propertiesStyle">
        ///    A <see cref="ReadStyle" /> value specifying at what level
        ///    of accuracy to read the media properties, or <see
        ///    cref="ReadStyle.None" /> to ignore the properties.
        /// </param>
        private void Read(ReadStyle propertiesStyle)
        {
            // TODO: Support Id3v2 boxes!!!
            tag  = new CombinedTag();
            Mode = AccessMode.Read;
            try {
                FileParser parser = new FileParser(this);

                if (propertiesStyle == ReadStyle.None)
                {
                    parser.ParseTag();
                }
                else
                {
                    parser.ParseTagAndProperties();
                }

                InvariantStartPosition = parser.MdatStartPosition;
                InvariantEndPosition   = parser.MdatEndPosition;

                udta_boxes.AddRange(parser.UserDataBoxes);

                // Ensure our collection contains at least a single empty box
                if (udta_boxes.Count == 0)
                {
                    IsoUserDataBox dummy = new IsoUserDataBox();
                    udta_boxes.Add(dummy);
                }

                // Check if a udta with ILST actually exists
                if (IsAppleTagUdtaPresent())
                {
                    TagTypesOnDisk |= TagTypes.Apple;                           //There is an udta present with ILST info
                }
                // Find the udta box with the Apple Tag ILST
                IsoUserDataBox udtaBox = FindAppleTagUdta();
                if (null == udtaBox)
                {
                    udtaBox = new IsoUserDataBox();
                }
                apple_tag = new AppleTag(udtaBox);
                tag.SetTags(apple_tag);

                // If we're not reading properties, we're done.
                if (propertiesStyle == ReadStyle.None)
                {
                    Mode = AccessMode.Closed;
                    return;
                }

                // Get the movie header box.
                IsoMovieHeaderBox mvhd_box = parser.MovieHeaderBox;
                if (mvhd_box == null)
                {
                    Mode = AccessMode.Closed;
                    throw new CorruptFileException(
                              "mvhd box not found.");
                }

                IsoAudioSampleEntry audio_sample_entry =
                    parser.AudioSampleEntry;
                IsoVisualSampleEntry visual_sample_entry =
                    parser.VisualSampleEntry;

                // Read the properties.
                properties = new Properties(mvhd_box.Duration,
                                            audio_sample_entry, visual_sample_entry);
            } finally {
                Mode = AccessMode.Closed;
            }
        }
示例#5
0
        /// <summary>
        ///    Saves the changes made in the current instance to the
        ///    file it represents.
        /// </summary>
        public override void Save()
        {
            if (udta_boxes.Count == 0)
            {
                IsoUserDataBox udtaBox = new IsoUserDataBox();
                udta_boxes.Add(udtaBox);
            }

            // Try to get into write mode.
            Mode = File.AccessMode.Write;
            try {
                FileParser parser = new FileParser(this);
                parser.ParseBoxHeaders();

                InvariantStartPosition = parser.MdatStartPosition;
                InvariantEndPosition   = parser.MdatEndPosition;

                long size_change    = 0;
                long write_position = 0;

                // To avoid rewriting udta blocks which might not have been modified,
                // the code here will work correctly if:
                // 1. There is a single udta for the entire file
                //   - OR -
                // 2. There are multiple utdtas, but only 1 of them contains the Apple ILST box.
                // We should be OK in the vast majority of cases
                IsoUserDataBox udtaBox = FindAppleTagUdta();
                if (null == udtaBox)
                {
                    udtaBox = new IsoUserDataBox();
                }
                ByteVector tag_data = udtaBox.Render();

                // If we don't have a "udta" box to overwrite...
                if (udtaBox.ParentTree == null ||
                    udtaBox.ParentTree.Length == 0)
                {
                    // Stick the box at the end of the moov box.
                    BoxHeader moov_header = parser.MoovTree [
                        parser.MoovTree.Length - 1];
                    size_change    = tag_data.Count;
                    write_position = moov_header.Position +
                                     moov_header.TotalBoxSize;
                    Insert(tag_data, write_position, 0);

                    // Overwrite the parent box sizes.
                    for (int i = parser.MoovTree.Length - 1; i >= 0;
                         i--)
                    {
                        size_change = parser.MoovTree [i
                                      ].Overwrite(this, size_change);
                    }
                }
                else
                {
                    // Overwrite the old box.
                    BoxHeader udta_header = udtaBox.ParentTree[udtaBox.ParentTree.Length - 1];
                    size_change = tag_data.Count -
                                  udta_header.TotalBoxSize;
                    write_position = udta_header.Position;
                    Insert(tag_data, write_position,
                           udta_header.TotalBoxSize);

                    // Overwrite the parent box sizes.
                    for (int i = udtaBox.ParentTree.Length - 2; i >= 0;
                         i--)
                    {
                        size_change = udtaBox.ParentTree [i
                                      ].Overwrite(this, size_change);
                    }
                }

                // If we've had a size change, we may need to adjust
                // chunk offsets.
                if (size_change != 0)
                {
                    // We may have moved the offset boxes, so we
                    // need to reread.
                    parser.ParseChunkOffsets();
                    InvariantStartPosition = parser.MdatStartPosition;
                    InvariantEndPosition   = parser.MdatEndPosition;

                    foreach (Box box in parser.ChunkOffsetBoxes)
                    {
                        IsoChunkLargeOffsetBox co64 =
                            box as IsoChunkLargeOffsetBox;

                        if (co64 != null)
                        {
                            co64.Overwrite(this,
                                           size_change,
                                           write_position);
                            continue;
                        }

                        IsoChunkOffsetBox stco =
                            box as IsoChunkOffsetBox;

                        if (stco != null)
                        {
                            stco.Overwrite(this,
                                           size_change,
                                           write_position);
                            continue;
                        }
                    }
                }

                TagTypesOnDisk = TagTypes;
            } finally {
                Mode = File.AccessMode.Closed;
            }
        }