/// <summary> /// Reads an audio packet, assigning the audio header and /// advancing the position to the next packet position. /// </summary> /// <param name="position"> /// A <see cref="long" /> value reference specifying the /// position at which to start reading the packet. This value /// is updated to the position of the next packet. /// </param> void ReadAudioPacket(ref long position) { Seek(position + 4); int length = ReadBlock(2).ToUShort(); if (!audio_found) { // There is a maximum of 16 stuffing bytes, read up to the PTS/DTS flags ByteVector packetHeaderBytes = this.ReadBlock(19); int i = 0; while (i < packetHeaderBytes.Count && packetHeaderBytes[i] == 0xFF) { // Byte is a stuffing byte i++; } if ((packetHeaderBytes[i] & 0x40) != 0) { // STD buffer size is unexpected for audio packets, but whatever i++; } // Decode the PTS/DTS flags byte timestampFlags = packetHeaderBytes[i]; long dataOffset = 4 + 2 + i + // Packet marker + packet length + stuffing bytes/STD buffer size ((timestampFlags & 0x20) > 0 ? 4 : 0) + // Presentation timestamp ((timestampFlags & 0x10) > 0 ? 4 : 0); // Decode timestamp audio_found = AudioHeader.Find(out audio_header, this, position + dataOffset, length - 9); } position += length; }
protected override void ReadStart(long start, ReadStyle propertiesStyle) { if (propertiesStyle != ReadStyle.None && !AudioHeader.Find(out first_header, this, start, 0x4000)) { throw new CorruptFileException("MPEG audio header not found."); } }
static AudioHeader() { sample_rates = new int[,] { { 0xac44, 0xbb80, 0x7d00, 0 }, { 0x5622, 0x5dc0, 0x3e80, 0 }, { 0x2b11, 0x2ee0, 0x1f40, 0 } }; block_size = new int[,] { { 0, 0x180, 0x480, 0x480 }, { 0, 0x180, 0x480, 0x240 }, { 0, 0x180, 0x480, 0x240 } }; bitrates = new int[,,] { { { 0, 0x20, 0x40, 0x60, 0x80, 160, 0xc0, 0xe0, 0x100, 0x120, 320, 0x160, 0x180, 0x1a0, 0x1c0, -1 }, { 0, 0x20, 0x30, 0x38, 0x40, 80, 0x60, 0x70, 0x80, 160, 0xc0, 0xe0, 0x100, 320, 0x180, -1 }, { 0, 0x20, 40, 0x30, 0x38, 0x40, 80, 0x60, 0x70, 0x80, 160, 0xc0, 0xe0, 0x100, 320, -1 } }, { { 0, 0x20, 0x30, 0x38, 0x40, 80, 0x60, 0x70, 0x80, 0x90, 160, 0xb0, 0xc0, 0xe0, 0x100, -1 }, { 0, 8, 0x10, 0x18, 0x20, 40, 0x30, 0x38, 0x40, 80, 0x60, 0x70, 0x80, 0x90, 160, -1 }, { 0, 8, 0x10, 0x18, 0x20, 40, 0x30, 0x38, 0x40, 80, 0x60, 0x70, 0x80, 0x90, 160, -1 } } }; Unknown = new AudioHeader(0, 0L, TagLib.Mpeg.XingHeader.Unknown, TagLib.Mpeg.VBRIHeader.Unknown); }
/// <summary> /// Reads format specific information at the start of the /// file. /// </summary> /// <param name="start"> /// A <see cref="long" /> value containing the seek position /// at which the tags end and the media data begins. /// </param> /// <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> /// <remarks> /// This method only searches for an audio header in the /// first 16384 bytes of code to avoid searching forever in /// corrupt files. /// </remarks> protected override void ReadStart(long start, ReadStyle propertiesStyle) { // Only check the first 16 bytes so we're not stuck // reading a bad file forever. if ((propertiesStyle & ReadStyle.Average) != 0 && !AudioHeader.Find(out first_header, this, start, 0x4000)) { throw new CorruptFileException("MPEG audio header not found."); } }
/// <summary> /// Searches for an audio header in a <see cref="TagLib.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="TagLib.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, TagLib.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] > 0xE0) { ByteVector data = buffer.Mid(i, 4); if (GetHeaderError(data) == null) { try { header = new AudioHeader( data, file, position + i); return(true); } catch (CorruptFileException) { } } } } position += File.BufferSize; } while (buffer.Count > 3 && (length < 0 || position < end)); return(false); }
/// <summary> /// Reads an audio packet, assigning the audio header and /// advancing the position to the next packet position. /// </summary> /// <param name="position"> /// A <see cref="long" /> value reference specifying the /// position at which to start reading the packet. This value /// is updated to the position of the next packet. /// </param> void ReadAudioPacket(ref long position) { Seek(position + 4); int length = ReadBlock(2).ToUShort(); if (!audio_found) { audio_found = AudioHeader.Find(out audio_header, this, position + 15, length - 9); } position += length; }
/// <summary> /// Searches for an audio header in a <see cref="TagLib.File" /// /> starting at a specified position and searching to the /// end of the file. /// </summary> /// <param name="header"> /// A <see cref="AudioHeader" /> object in which the found /// header will be stored. /// </param> /// <param name="file"> /// A <see cref="TagLib.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> /// <returns> /// A <see cref="bool" /> value indicating whether or not a /// header was found. /// </returns> /// <remarks> /// Searching to the end of the file can be very, very slow /// especially for corrupt or non-MPEG files. It is /// recommended to use <see /// cref="Find(AudioHeader,TagLib.File,long,int)" /> /// instead. /// </remarks> public static bool Find(out AudioHeader header, TagLib.File file, long position) { return(Find(out header, file, position, -1)); }
/// <summary> /// Searches for an audio header in a <see cref="TagLib.File" /// /> starting at a specified position and searching to the /// end of the file. /// </summary> /// <param name="header"> /// A <see cref="AudioHeader" /> object in which the found /// header will be stored. /// </param> /// <param name="file"> /// A <see cref="TagLib.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> /// <returns> /// A <see cref="bool" /> value indicating whether or not a /// header was found. /// </returns> /// <remarks> /// Searching to the end of the file can be very, very slow /// especially for corrupt or non-MPEG files. It is /// recommended to use <see /// cref="Find(AudioHeader&,TagLib.File,long,int)" /> /// instead. /// </remarks> public static bool Find (out AudioHeader header, TagLib.File file, long position) { return Find (out header, file, position, -1); }
/// <summary> /// Searches for an audio header in a <see cref="TagLib.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="TagLib.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, TagLib.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] > 0xE0) try { header = new AudioHeader ( buffer.Mid (i, 4), file, position + i); return true; } catch (CorruptFileException) { } position += File.BufferSize; } while (buffer.Count > 3 && (length < 0 || position < end)); return false; }
public static bool Find(out AudioHeader header, TagLib.File file, long position, int length) { if (file == null) { throw new ArgumentNullException("file"); } long num = position + length; header = Unknown; file.Seek(position); ByteVector vector = file.ReadBlock(3); if (vector.Count >= 3) { do { file.Seek(position + 3L); vector = vector.Mid(vector.Count - 3); vector.Add(file.ReadBlock((int) TagLib.File.BufferSize)); for (int i = 0; (i < (vector.Count - 3)) && ((length < 0) || ((position + i) < num)); i++) { if ((vector[i] == 0xff) && (vector[i + 1] > 0xe0)) { try { header = new AudioHeader(vector.Mid(i, 4), file, position + i); return true; } catch (CorruptFileException) { } } } position += TagLib.File.BufferSize; } while ((vector.Count > 3) && ((length < 0) || (position < num))); } return false; }