/// <summary> /// Constructs and initializes a new instance of <see /// cref="FullBox" /> with a provided header and handler by /// reading the contents from a specified file. /// </summary> /// <param name="header"> /// A <see cref="BoxHeader" /> object containing the header /// to use for the new instance. /// </param> /// <param name="file"> /// A <see cref="TagLibSharp.File" /> object to read the contents /// of the box from. /// </param> /// <param name="handler"> /// A <see cref="IsoHandlerBox" /> object containing the /// handler that applies to the new instance. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="file" /> is <see langword="null" />. /// </exception> protected FullBox(BoxHeader header, TagLibSharp.File file, IsoHandlerBox handler) : base(header, handler) { if (file == null) { throw new ArgumentNullException("file"); } file.Seek(base.DataPosition); ByteVector header_data = file.ReadBlock(4); version = header_data [0]; flags = header_data.Mid(1, 3).ToUInt(); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="List" /> by reading the contents of a raw RIFF list /// from a specified position in a <see cref="TagLibSharp.File"/>. /// </summary> /// <param name="file"> /// A <see cref="TagLibSharp.File" /> object containing the file /// from which the contents of the new instance is to be /// read. /// </param> /// <param name="position"> /// A <see cref="long" /> value specify at what position to /// read the list. /// </param> /// <param name="length"> /// A <see cref="int" /> value specifying the number of bytes /// to read. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="file" /> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="position" /> is less than zero or greater /// than the size of the file. /// </exception> public List(TagLibSharp.File file, long position, int length) { if (file == null) { throw new ArgumentNullException("file"); } if (length < 0) { throw new ArgumentOutOfRangeException( "length"); } if (position < 0 || position > file.Length - length) { throw new ArgumentOutOfRangeException( "position"); } file.Seek(position); Parse(file.ReadBlock(length)); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="IsoHandlerBox" /> with a provided header and /// handler by reading the contents from a specified file. /// </summary> /// <param name="header"> /// A <see cref="BoxHeader" /> object containing the header /// to use for the new instance. /// </param> /// <param name="file"> /// A <see cref="TagLibSharp.File" /> object to read the contents /// of the box from. /// </param> /// <param name="handler"> /// A <see cref="IsoHandlerBox" /> object containing the /// handler that applies to the new instance. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="file" /> is <see langword="null" />. /// </exception> public IsoHandlerBox(BoxHeader header, TagLibSharp.File file, IsoHandlerBox handler) : base(header, file, handler) { if (file == null) { throw new System.ArgumentNullException("file"); } file.Seek(DataPosition + 4); ByteVector box_data = file.ReadBlock(DataSize - 4); handler_type = box_data.Mid(0, 4); int end = box_data.Find((byte)0, 16); if (end < 16) { end = box_data.Count; } name = box_data.ToString(StringType.UTF8, 16, end - 16); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="VideoHeader" /> by reading it from a specified /// location in a specified file. /// </summary> /// <param name="file"> /// A <see cref="TagLibSharp.File" /> object to read from. /// </param> /// <param name="position"> /// A <see cref="long" /> value indicating the position in /// <paramref name="file" /> at which the header begins. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="file" /> is <see langword="null" />. /// </exception> /// <exception cref="CorruptFileException"> /// Insufficient data could be read for the header. /// </exception> public VideoHeader(TagLibSharp.File file, long position) { if (file == null) { throw new ArgumentNullException("file"); } file.Seek(position); ByteVector data = file.ReadBlock(7); if (data.Count < 7) { throw new CorruptFileException( "Insufficient data in header."); } width = data.Mid(0, 2).ToUShort() >> 4; height = data.Mid(1, 2).ToUShort() & 0x0FFF; frame_rate_index = data [3] & 0x0F; bitrate = (int)((data.Mid(4, 3).ToUInt() >> 6) & 0x3FFFF); }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="IsoMovieHeaderBox" /> with a provided header and /// handler by reading the contents from a specified file. /// </summary> /// <param name="header"> /// A <see cref="BoxHeader" /> object containing the header /// to use for the new instance. /// </param> /// <param name="file"> /// A <see cref="TagLibSharp.File" /> object to read the contents /// of the box from. /// </param> /// <param name="handler"> /// A <see cref="IsoHandlerBox" /> object containing the /// handler that applies to the new instance. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="file" /> is <see langword="null" />. /// </exception> public IsoMovieHeaderBox(BoxHeader header, TagLibSharp.File file, IsoHandlerBox handler) : base(header, file, handler) { if (file == null) { throw new ArgumentNullException("file"); } int bytes_remaining = DataSize; ByteVector data; if (Version == 1) { // Read version one (large integers). data = file.ReadBlock(Math.Min(28, bytes_remaining)); if (data.Count >= 8) { creation_time = data.Mid(0, 8).ToULong(); } if (data.Count >= 16) { modification_time = data.Mid(8, 8).ToULong(); } if (data.Count >= 20) { timescale = data.Mid(16, 4).ToUInt(); } if (data.Count >= 28) { duration = data.Mid(20, 8).ToULong(); } bytes_remaining -= 28; } else { // Read version zero (normal integers). data = file.ReadBlock(Math.Min(16, bytes_remaining)); if (data.Count >= 4) { creation_time = data.Mid(0, 4).ToUInt(); } if (data.Count >= 8) { modification_time = data.Mid(4, 4).ToUInt(); } if (data.Count >= 12) { timescale = data.Mid(8, 4).ToUInt(); } if (data.Count >= 16) { duration = data.Mid(12, 4).ToUInt(); } bytes_remaining -= 16; } data = file.ReadBlock(Math.Min(6, bytes_remaining)); if (data.Count >= 4) { rate = data.Mid(0, 4).ToUInt(); } if (data.Count >= 6) { volume = data.Mid(4, 2).ToUShort(); } file.Seek(file.Tell + 70); bytes_remaining -= 76; data = file.ReadBlock(Math.Min(4, bytes_remaining)); if (data.Count >= 4) { next_track_id = data.Mid(0, 4).ToUInt(); } }
/// <summary> /// Constructs and initializes a new instance of <see /// cref="AudioHeader" /> by reading its contents from a /// <see cref="ByteVector" /> object and its Xing Header from /// the appropriate location in the specified file. /// </summary> /// <param name="data"> /// A <see cref="ByteVector" /> object containing the header /// to read. /// </param> /// <param name="file"> /// A <see cref="TagLibSharp.File" /> object to read the Xing /// header from. /// </param> /// <param name="position"> /// A <see cref="long" /> value indicating the position in /// <paramref name="file" /> at which the header begins. /// </param> /// <exception cref="CorruptFileException"> /// <paramref name="data" /> is less than 4 bytes long, /// does not begin with a MPEG audio synch, has a negative /// bitrate, or has a sample rate of zero. /// </exception> private AudioHeader(ByteVector data, TagLibSharp.File file, long position) { this.duration = TimeSpan.Zero; stream_length = 0; if (data.Count < 4) { throw new CorruptFileException( "Insufficient header length."); } if (data [0] != 0xFF) { throw new CorruptFileException( "First byte did not match MPEG synch."); } // Checking bits from high to low: // // First 3 bits MUST be set. Bits 4 and 5 can // be 00, 10, or 11 but not 01. One or more of // bits 6 and 7 must be set. Bit 8 can be // anything. if ((data [1] & 0xE6) <= 0xE0 || (data [1] & 0x18) == 0x08) { throw new CorruptFileException( "Second byte did not match MPEG synch."); } flags = data.ToUInt(); if (((flags >> 12) & 0x0F) == 0x0F) { throw new CorruptFileException( "Header uses invalid bitrate index."); } if (((flags >> 10) & 0x03) == 0x03) { throw new CorruptFileException( "Invalid sample rate."); } xing_header = XingHeader.Unknown; vbri_header = VBRIHeader.Unknown; // Check for a Xing header that will help us in // gathering information about a VBR stream. file.Seek(position + XingHeader.XingHeaderOffset( Version, ChannelMode)); ByteVector xing_data = file.ReadBlock(16); if (xing_data.Count == 16 && xing_data.StartsWith( XingHeader.FileIdentifier)) { xing_header = new XingHeader(xing_data); } if (xing_header.Present) { return; } // A Xing header could not be found, next chec for a // Fraunhofer VBRI header. file.Seek(position + VBRIHeader.VBRIHeaderOffset()); // Only get the first 24 bytes of the Header. // We're not interested in the TOC entries. ByteVector vbri_data = file.ReadBlock(24); if (vbri_data.Count == 24 && vbri_data.StartsWith(VBRIHeader.FileIdentifier)) { vbri_header = new VBRIHeader(vbri_data); } }
/// <summary> /// Searches for an audio header in a <see cref="TagLibSharp.File" /// /> starting at a specified position and searching through /// a specified number of bytes. /// </summary> /// <param name="header"> /// A <see cref="AudioHeader" /> object in which the found /// header will be stored. /// </param> /// <param name="file"> /// A <see cref="TagLibSharp.File" /> object to search. /// </param> /// <param name="position"> /// A <see cref="long" /> value specifying the seek position /// in <paramref name="file" /> at which to start searching. /// </param> /// <param name="length"> /// A <see cref="int" /> value specifying the maximum number /// of bytes to search before aborting. /// </param> /// <returns> /// A <see cref="bool" /> value indicating whether or not a /// header was found. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="file" /> is <see langword="null" />. /// </exception> public static bool Find(out AudioHeader header, TagLibSharp.File file, long position, int length) { if (file == null) { throw new ArgumentNullException("file"); } long end = position + length; header = AudioHeader.Unknown; file.Seek(position); ByteVector buffer = file.ReadBlock(3); if (buffer.Count < 3) { return(false); } do { file.Seek(position + 3); buffer = buffer.Mid(buffer.Count - 3); buffer.Add(file.ReadBlock( (int)File.BufferSize)); for (int i = 0; i < buffer.Count - 3 && (length < 0 || position + i < end); i++) { if (buffer[i] == 0xFF && buffer[i + 1] >= 0xF0) // 0xFFF { try { BitStream bits = new BitStream(buffer.Mid(i, 7).Data); // 12 bits sync header bits.ReadInt32(12); // 1 bit mpeg 2/4 bits.ReadInt32(1); // 2 bits layer bits.ReadInt32(2); // 1 bit protection absent bits.ReadInt32(1); // 2 bits profile object type bits.ReadInt32(2); // 4 bits sampling frequency index int samplerateindex = bits.ReadInt32(4); if (samplerateindex >= sample_rates.Length) { return(false); } long samplerate = sample_rates[samplerateindex]; // 1 bit private bit bits.ReadInt32(1); // 3 bits channel configuration int channelconfigindex = bits.ReadInt32(3); if (channelconfigindex >= channels.Length) { return(false); } // 4 copyright bits bits.ReadInt32(4); // 13 bits frame length long framelength = bits.ReadInt32(13); // double check framelength if (framelength < 7) { return(false); } // 11 bits buffer fullness bits.ReadInt32(11); // 2 bits number of raw data blocks in frame int numberofframes = bits.ReadInt32(2) + 1; long numberofsamples = numberofframes * 1024; long bitrate = framelength * 8 * samplerate / numberofsamples; header = new AudioHeader(channels[channelconfigindex], (int)bitrate, (int)samplerate, (int)numberofsamples, numberofframes); return(true); } catch (CorruptFileException) { } } } position += File.BufferSize; } while (buffer.Count > 3 && (length < 0 || position < end)); return(false); }