/// <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="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> public override Tag GetTag(TagTypes type, bool create) { Tag tag = null; switch (type) { case TagTypes.Id3v2: if (id32_tag == null && create) { id32_tag = new Id3v2.Tag(); id32_tag.Version = 4; id32_tag.Flags |= Id3v2.HeaderFlags .FooterPresent; this.tag.CopyTo(id32_tag, true); } tag = id32_tag; break; case TagTypes.RiffInfo: if (info_tag == null && create) { info_tag = new InfoTag(); this.tag.CopyTo(info_tag, true); } tag = info_tag; break; case TagTypes.MovieId: if (mid_tag == null && create) { mid_tag = new MovieIdTag(); this.tag.CopyTo(mid_tag, true); } tag = mid_tag; break; case TagTypes.DivX: if (divx_tag == null && create) { divx_tag = new DivXTag(); this.tag.CopyTo(divx_tag, true); } tag = divx_tag; break; } this.tag.SetTags(id32_tag, info_tag, mid_tag, divx_tag); return(tag); }
/// <summary> /// Removes a set of tag types from the current instance. /// </summary> /// <param name="types"> /// A bitwise combined <see cref="TagTypes" /> value /// containing tag types to be removed from the file. /// </param> /// <remarks> /// In order to remove all tags from a file, pass <see /// cref="TagTypes.AllTags" /> as <paramref name="types" />. /// </remarks> public override void RemoveTags(TagTypes types) { if ((types & TagTypes.Id3v2) != TagTypes.None) { id32_tag = null; } if ((types & TagTypes.RiffInfo) != TagTypes.None) { info_tag = null; } if ((types & TagTypes.MovieId) != TagTypes.None) { mid_tag = null; } if ((types & TagTypes.DivX) != TagTypes.None) { divx_tag = null; } tag.SetTags(id32_tag, info_tag, mid_tag, divx_tag); }
/// <summary> /// Reads the contents of the current instance determining /// the size of the riff data, the area the tagging is in, /// and optionally reading in the tags and media properties. /// </summary> /// <param name="read_tags"> /// If <see langword="true" />, any tags found will be read /// into the current instance. /// </param> /// <param name="style"> /// A <see cref="ReadStyle"/> value specifying how the media /// data is to be read into the current instance. /// </param> /// <param name="riff_size"> /// A <see cref="uint"/> value reference to be filled with /// the size of the RIFF data as read from the file. /// </param> /// <param name="tag_start"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// starts. /// </param> /// <param name="tag_end"> /// A <see cref="long" /> value reference to be filled with /// the absolute seek position at which the tagging data /// ends. /// </param> /// <exception cref="CorruptFileException"> /// The file does not begin with <see cref="FileIdentifier" /// />. /// </exception> private void Read(bool read_tags, ReadStyle style, out uint riff_size, out long tag_start, out long tag_end) { Seek(0); if (ReadBlock(4) != FileIdentifier) { throw new CorruptFileException( "File does not begin with RIFF identifier"); } riff_size = ReadBlock(4).ToUInt(false); ByteVector stream_format = ReadBlock(4); tag_start = -1; tag_end = -1; long position = 12; long length = Length; uint size = 0; TimeSpan duration = TimeSpan.Zero; ICodec [] codecs = new ICodec [0]; // Read until there are less than 8 bytes to read. do { bool tag_found = false; Seek(position); string fourcc = ReadBlock(4).ToString(StringType.UTF8); size = ReadBlock(4).ToUInt(false); switch (fourcc) { // "fmt " is used by Wave files to hold the // WaveFormatEx structure. case "fmt ": if (style == ReadStyle.None || stream_format != "WAVE") { break; } Seek(position + 8); codecs = new ICodec [] { new WaveFormatEx(ReadBlock(18), 0) }; break; // "data" contains the audio data for wave // files. It's contents represent the invariant // portion of the file and is used to determine // the duration of a file. It should always // appear after "fmt ". case "data": if (stream_format != "WAVE") { break; } InvariantStartPosition = position; InvariantEndPosition = position + size; if (style == ReadStyle.None || codecs.Length != 1 || !(codecs [0] is WaveFormatEx)) { break; } duration += TimeSpan.FromSeconds( (double)size / (double) ((WaveFormatEx)codecs [0]) .AverageBytesPerSecond); break; // Lists are used to store a variety of data // collections. Read the type and act on it. case "LIST": { switch (ReadBlock(4).ToString(StringType.UTF8)) { // "hdlr" is used by AVI files to hold // a media header and BitmapInfoHeader // and WaveFormatEx structures. case "hdrl": if (style == ReadStyle.None || stream_format != "AVI ") { continue; } AviHeaderList header_list = new AviHeaderList(this, position + 12, (int)(size - 4)); duration = header_list.Header.Duration; codecs = header_list.Codecs; break; // "INFO" is a tagging format handled by // the InfoTag class. case "INFO": if (read_tags && info_tag == null) { info_tag = new InfoTag( this, position + 12, (int)(size - 4)); } tag_found = true; break; // "MID " is a tagging format handled by // the MovieIdTag class. case "MID ": if (read_tags && mid_tag == null) { mid_tag = new MovieIdTag( this, position + 12, (int)(size - 4)); } tag_found = true; break; // "movi" contains the media data for // and AVI and its contents represent // the invariant portion of the file. case "movi": if (stream_format != "AVI ") { break; } InvariantStartPosition = position; InvariantEndPosition = position + size; break; } break; } // "ID32" is a custom box for this format that // contains an ID3v2 tag. case "ID32": if (read_tags && id32_tag == null) { id32_tag = new Id3v2.Tag(this, position + 8); } tag_found = true; break; // "IDVX" is used by DivX and holds an ID3v1- // style tag. case "IDVX": if (read_tags && divx_tag == null) { divx_tag = new DivXTag(this, position + 8); } tag_found = true; break; // "JUNK" is a padding element that could be // associated with tag data. case "JUNK": if (tag_end == position) { tag_end = position + 8 + size; } break; } // Determine the region of the file that // contains tags. if (tag_found) { if (tag_start == -1) { tag_start = position; tag_end = position + 8 + size; } else if (tag_end == position) { tag_end = position + 8 + size; } } // Move to the next item. } while ((position += 8 + size) + 8 < length); // If we're reading properties, and one were found, // throw an exception. Otherwise, create the Properties // object. if (style != ReadStyle.None) { if (codecs.Length == 0) { throw new UnsupportedFormatException( "Unsupported RIFF type."); } properties = new Properties(duration, codecs); } // If we're reading tags, update the combined tag. if (read_tags) { tag.SetTags(id32_tag, info_tag, mid_tag, divx_tag); } }