Пример #1
0
        private void readAllBlocks(BufferedBinaryReader source)
        {
            OggHeader header = new OggHeader();

            // Start from the 1st page following headers
            byte typeFlag;
            byte nbLacingValues;

            byte[] lacingValues    = new byte[255];
            long   nextPageOffset  = 0;
            ulong  lastAbsPosition = 0;

            source.Seek(info.SetupHeaderEnd, SeekOrigin.Begin);

            // Iterate until last page is encountered
            do
            {
                source.Seek(nextPageOffset, SeekOrigin.Current);

                header.ReadFromStream(source);

                nbLacingValues = header.Segments;
                typeFlag       = header.TypeFlag;
                nextPageOffset = header.GetPageLength();

                System.Console.WriteLine(header.AbsolutePosition - lastAbsPosition + ";" + nextPageOffset);
                lastAbsPosition = header.AbsolutePosition;
            } while (0 == (typeFlag & 0x04)); // 0x04 marks the last page of the logical bitstream
        }
Пример #2
0
        // ---------------------------------------------------------------------------

        private long GetSamples(BinaryReader Source)
        {
            int DataIndex;

            // Using byte instead of char here to avoid mistaking range of bytes for unicode chars
            byte[]    Data   = new byte[251];
            OggHeader Header = new OggHeader();

            // Get total number of samples
            int result = 0;

            for (int index = 1; index <= 50; index++)
            {
                DataIndex = (int)(Source.BaseStream.Length - (/*Data.Length*/ 251 - 10) * index - 10);
                Source.BaseStream.Seek(DataIndex, SeekOrigin.Begin);
                Data = Source.ReadBytes(251);

                // Get number of PCM samples from last Ogg packet header
                for (int iterator = 251 - 10; iterator >= 0; iterator--)
                {
                    char[] tempArray = new char[4] {
                        (char)Data[iterator],
                        (char)Data[iterator + 1],
                        (char)Data[iterator + 2],
                        (char)Data[iterator + 3]
                    };
                    if (Utils.StringEqualsArr(OGG_PAGE_ID, tempArray))
                    {
                        Source.BaseStream.Seek(DataIndex + iterator, SeekOrigin.Begin);

                        Header.ID               = Source.ReadChars(4);
                        Header.StreamVersion    = Source.ReadByte();
                        Header.TypeFlag         = Source.ReadByte();
                        Header.AbsolutePosition = Source.ReadInt64();
                        Header.Serial           = Source.ReadInt32();
                        Header.PageNumber       = Source.ReadInt32();
                        Header.Checksum         = Source.ReadInt32();
                        Header.Segments         = Source.ReadByte();
                        Header.LacingValues     = Source.ReadBytes(0xFF);
                        return(Header.AbsolutePosition);
                    }
                }
            }
            return(result);
        }
Пример #3
0
        private void CalculateChecksumAndWriteOggHeaderToBinaryWriter(OggHeader oggHeader, byte[] data)
        {
            var oggHeaderBytes = ArrayPool <byte> .Shared.Rent(oggHeader.Size);

            try
            {
                var spanWriter = new SpanWriter(oggHeaderBytes);
                spanWriter.WriteOggHeader(oggHeader);

                var checkSum = OggCRC32.CalculateCRC(0, oggHeaderBytes.AsSpan().Slice(0, oggHeader.Size), data);
                spanWriter.Write(checkSum, OggHeader.CheckSumLocation);

                _writer.Write(oggHeaderBytes, 0, oggHeader.Size);
            }
            finally
            {
                ArrayPool <byte> .Shared.Return(oggHeaderBytes);
            }

            _writer.Write(data);
        }
Пример #4
0
        public void WriteOggPage(OggHeaderType oggHeaderType, byte numberOfSegments, List <SegmentEntry> oggPages)
        {
            var data = oggPages.SelectMany(o => o.Data).ToArray();

            _granulePosition += (ulong)oggPages.Sum(op => op.NumberOfSamples * op.NumberOfFrames);

            var oggHeader = new OggHeader
            {
                StreamVersion   = 0,
                TypeFlag        = oggHeaderType,
                GranulePosition = _granulePosition,
                Serial          = _serial,
                PageNumber      = _page,
                Checksum        = 0,
                TotalSegments   = numberOfSegments,
                SegmentTable    = oggPages.SelectMany(o => o.SegmentBytes).ToArray()
            };

            CalculateChecksumAndWriteOggHeaderToBinaryWriter(oggHeader, data);

            _writer.Flush();

            _page++;
        }
Пример #5
0
        // Specific implementation for OGG container (multiple pages with limited size)

        // TODO DOC
        // Simplified implementation of MetaDataIO tweaked for OGG-Vorbis specifics, i.e.
        //  - tag spans over multiple pages, each having its own header
        //  - last page may include whole or part of 3rd Vorbis header (setup header)

        public bool Write(BinaryReader r, BinaryWriter w, TagData tag)
        {
            bool result         = true;
            int  writtenPages   = 0;
            long nextPageOffset = 0;

            // Read all the fields in the existing tag (including unsupported fields)
            ReadTagParams readTagParams = new ReadTagParams(true, true);

            readTagParams.PrepareForWriting = true;
            Read(r, readTagParams);

            // Get "unpaged" virtual stream to be written, containing the vorbis tag (=comment header)
            using (MemoryStream stream = new MemoryStream((int)(info.SetupHeaderEnd - info.CommentHeaderStart)))
            {
                stream.Write(Utils.Latin1Encoding.GetBytes(VORBIS_TAG_ID), 0, VORBIS_TAG_ID.Length);
                vorbisTag.Write(stream, tag);

                long newTagSize      = stream.Position;
                int  setupHeaderSize = (int)(info.SetupHeaderEnd - info.SetupHeaderStart);

                // Append the setup header in the "unpaged" virtual stream
                r.BaseStream.Seek(info.SetupHeaderStart, SeekOrigin.Begin);
                if (1 == info.SetupHeaderSpanPages)
                {
                    StreamUtils.CopyStream(r.BaseStream, stream, setupHeaderSize);
                }
                else
                {
                    // TODO - handle case where initial setup header spans across two pages
                    LogDelegator.GetLogDelegate()(Log.LV_ERROR, "ATL does not yet handle the case where Vorbis setup header spans across two OGG pages");
                    return(false);
                }


                // Construct the entire segments table
                int  commentsHeader_nbSegments = (int)Math.Ceiling(1.0 * newTagSize / 255);
                byte commentsHeader_remainingBytesInLastSegment = (byte)(newTagSize % 255);

                int  setupHeader_nbSegments = (int)Math.Ceiling(1.0 * setupHeaderSize / 255);
                byte setupHeader_remainingBytesInLastSegment = (byte)(setupHeaderSize % 255);

                byte[] entireSegmentsTable = new byte[commentsHeader_nbSegments + setupHeader_nbSegments];
                for (int i = 0; i < commentsHeader_nbSegments - 1; i++)
                {
                    entireSegmentsTable[i] = 255;
                }
                entireSegmentsTable[commentsHeader_nbSegments - 1] = commentsHeader_remainingBytesInLastSegment;
                for (int i = commentsHeader_nbSegments; i < commentsHeader_nbSegments + setupHeader_nbSegments - 1; i++)
                {
                    entireSegmentsTable[i] = 255;
                }
                entireSegmentsTable[commentsHeader_nbSegments + setupHeader_nbSegments - 1] = setupHeader_remainingBytesInLastSegment;

                int nbPageHeaders        = (int)Math.Ceiling((commentsHeader_nbSegments + setupHeader_nbSegments) / 255.0);
                int totalPageHeadersSize = (nbPageHeaders * 27) + setupHeader_nbSegments + commentsHeader_nbSegments;


                // Resize the whole virtual stream once and for all to avoid multiple reallocations while repaging
                stream.SetLength(stream.Position + totalPageHeadersSize);


                /// Repage comments header & setup header within the virtual stream
                stream.Seek(0, SeekOrigin.Begin);

                OggHeader header = new OggHeader()
                {
                    ID               = OGG_PAGE_ID,
                    StreamVersion    = info.CommentHeader.StreamVersion,
                    TypeFlag         = 0,
                    AbsolutePosition = ulong.MaxValue,
                    Serial           = info.CommentHeader.Serial,
                    PageNumber       = 1,
                    Checksum         = 0
                };

                int  segmentsLeftToPage = commentsHeader_nbSegments + setupHeader_nbSegments;
                int  bytesLeftToPage    = (int)newTagSize + setupHeaderSize;
                int  pagedSegments      = 0;
                int  pagedBytes         = 0;
                long position;

                BinaryWriter virtualW = new BinaryWriter(stream);
                IList <KeyValuePair <long, int> > pageHeaderOffsets = new List <KeyValuePair <long, int> >();

                // Repaging
                while (segmentsLeftToPage > 0)
                {
                    header.Segments     = (byte)Math.Min(255, segmentsLeftToPage);
                    header.LacingValues = new byte[header.Segments];
                    if (segmentsLeftToPage == header.Segments)
                    {
                        header.AbsolutePosition = 0;                                        // Last header page has its absolutePosition = 0
                    }
                    Array.Copy(entireSegmentsTable, pagedSegments, header.LacingValues, 0, header.Segments);

                    position = stream.Position;
                    // Push current data to write header
                    StreamUtils.CopySameStream(stream, stream.Position, stream.Position + header.GetHeaderSize(), bytesLeftToPage);
                    stream.Seek(position, SeekOrigin.Begin);

                    pageHeaderOffsets.Add(new KeyValuePair <long, int>(position, header.GetPageLength() + header.GetHeaderSize()));

                    header.WriteToStream(virtualW);
                    stream.Seek(header.GetPageLength(), SeekOrigin.Current);

                    pagedSegments      += header.Segments;
                    segmentsLeftToPage -= header.Segments;
                    pagedBytes         += header.GetPageLength();
                    bytesLeftToPage    -= header.GetPageLength();

                    header.PageNumber++;
                    if (0 == header.TypeFlag)
                    {
                        header.TypeFlag = 1;
                    }
                }
                writtenPages = header.PageNumber - 1;


                // Generate CRC32 of created pages
                uint   crc;
                byte[] data;
                foreach (KeyValuePair <long, int> kv in pageHeaderOffsets)
                {
                    crc = 0;
                    stream.Seek(kv.Key, SeekOrigin.Begin);
                    data = new byte[kv.Value];
                    stream.Read(data, 0, kv.Value);
                    crc = OggCRC32.CalculateCRC(crc, data, (uint)kv.Value);
                    stream.Seek(kv.Key + 22, SeekOrigin.Begin); // Position of CRC within OGG header
                    virtualW.Write(crc);
                }


                /// Insert the virtual paged stream into the actual file
                long oldHeadersSize = info.SetupHeaderEnd - info.CommentHeaderStart;
                long newHeadersSize = stream.Length;

                if (newHeadersSize > oldHeadersSize) // Need to build a larger file
                {
                    StreamUtils.LengthenStream(w.BaseStream, info.CommentHeaderEnd, (uint)(newHeadersSize - oldHeadersSize));
                }
                else if (newHeadersSize < oldHeadersSize) // Need to reduce file size
                {
                    StreamUtils.ShortenStream(w.BaseStream, info.CommentHeaderEnd, (uint)(oldHeadersSize - newHeadersSize));
                }

                // Rewrite Comment and Setup headers
                w.BaseStream.Seek(info.CommentHeaderStart, SeekOrigin.Begin);
                stream.Seek(0, SeekOrigin.Begin);

                StreamUtils.CopyStream(stream, w.BaseStream);

                nextPageOffset = info.CommentHeaderStart + stream.Length;
            }

            // If the number of written pages is different than the number of previous existing pages,
            // all the next pages of the file need to be renumbered, and their CRC accordingly recalculated
            if (writtenPages != info.CommentHeaderSpanPages + info.SetupHeaderSpanPages - 1)
            {
                OggHeader header = new OggHeader();
                byte[]    data;
                uint      crc;

                do
                {
                    w.BaseStream.Seek(nextPageOffset, SeekOrigin.Begin);
                    header.ReadFromStream(r);

                    if (header.IsValid())
                    {
                        // Rewrite page number
                        writtenPages++;
                        w.BaseStream.Seek(nextPageOffset + 18, SeekOrigin.Begin);
                        w.Write(writtenPages);

                        // Rewrite CRC
                        w.BaseStream.Seek(nextPageOffset, SeekOrigin.Begin);
                        data = new byte[header.GetHeaderSize() + header.GetPageLength()];
                        r.Read(data, 0, data.Length);

                        // Checksum has to include its own location, as if it were 0
                        data[22] = 0;
                        data[23] = 0;
                        data[24] = 0;
                        data[25] = 0;

                        crc = OggCRC32.CalculateCRC(0, data, (uint)data.Length);
                        r.BaseStream.Seek(nextPageOffset + 22, SeekOrigin.Begin); // Position of CRC within OGG header
                        w.Write(crc);

                        // To the next header
                        nextPageOffset += data.Length;
                    }
                    else
                    {
                        LogDelegator.GetLogDelegate()(Log.LV_ERROR, "Invalid OGG header found; aborting writing operation"); // Throw exception ?
                        return(false);
                    }
                } while (0 == (header.TypeFlag & 0x04));  // 0x04 marks the last page of the logical bitstream
            }

            return(result);
        }
Пример #6
0
        // ---------------------------------------------------------------------------

        // Read total samples of OGG file, which are located on the very last page of the file
        private ulong getSamples(BufferedBinaryReader source)
        {
            OggHeader header = new OggHeader();

            string headerId;
            byte   typeFlag;

            byte[] lacingValues   = new byte[255];
            byte   nbLacingValues = 0;
            long   nextPageOffset = 0;

            // TODO - fine tune seekSize value
            int seekSize = (int)Math.Round(MAX_PAGE_SIZE * 0.75);

            if (seekSize > source.Length)
            {
                seekSize = (int)Math.Round(source.Length * 0.5);
            }
            source.Seek(-seekSize, SeekOrigin.End);
            if (!StreamUtils.FindSequence(source, Utils.Latin1Encoding.GetBytes(OGG_PAGE_ID)))
            {
                LogDelegator.GetLogDelegate()(Log.LV_ERROR, "No OGG header found; aborting read operation"); // Throw exception ?
                return(0);
            }
            source.Seek(-4, SeekOrigin.Current);

            // Iterate until last page is encountered
            do
            {
                if (source.Position + nextPageOffset + 27 > source.Length) // End of stream about to be reached => last OGG header did not have the proper type flag
                {
                    break;
                }

                source.Seek(nextPageOffset, SeekOrigin.Current);

                headerId = Utils.Latin1Encoding.GetString(source.ReadBytes(4));

                if (headerId.Equals(OGG_PAGE_ID))
                {
                    source.Seek(1, SeekOrigin.Current);
                    typeFlag = source.ReadByte();
                    source.Seek(20, SeekOrigin.Current);
                    nbLacingValues = source.ReadByte();
                    nextPageOffset = 0;
                    source.Read(lacingValues, 0, nbLacingValues);
                    for (int i = 0; i < nbLacingValues; i++)
                    {
                        nextPageOffset += lacingValues[i];
                    }
                }
                else
                {
                    LogDelegator.GetLogDelegate()(Log.LV_ERROR, "Invalid OGG header found while looking for total samples; aborting read operation"); // Throw exception ?
                    return(0);
                }
            } while (0 == (typeFlag & 0x04)); // 0x04 marks the last page of the logical bitstream


            // Stream is positioned at the end of the last page header; backtracking to read AbsolutePosition field
            source.Seek(-nbLacingValues - 21, SeekOrigin.Current);

            return(source.ReadUInt64());
        }
Пример #7
0
		// ---------------------------------------------------------------------------

		private long GetSamples(BinaryReader Source)
		{  
			int DataIndex;	
			// Using byte instead of char here to avoid mistaking range of bytes for unicode chars
			byte[] Data = new byte[251];
			OggHeader Header = new OggHeader();

			// Get total number of samples
			int result = 0;

			for (int index=1; index<=50; index++)
			{
				DataIndex = (int)(Source.BaseStream.Length - (/*Data.Length*/251 - 10) * index - 10);
				Source.BaseStream.Seek(DataIndex, SeekOrigin.Begin);
				Data = Source.ReadBytes(251);

				// Get number of PCM samples from last Ogg packet header
				for (int iterator=251 - 10; iterator>=0; iterator--)
				{
					char[] tempArray = new char[4] { (char)Data[iterator],
													   (char)Data[iterator + 1],
													   (char)Data[iterator + 2],
													   (char)Data[iterator + 3] };
					if ( Utils.StringEqualsArr(OGG_PAGE_ID,tempArray) ) 
					{
						Source.BaseStream.Seek(DataIndex + iterator, SeekOrigin.Begin);
        
						Header.ID = Source.ReadChars(4);
						Header.StreamVersion = Source.ReadByte();
						Header.TypeFlag = Source.ReadByte();
						Header.AbsolutePosition = Source.ReadInt64();
						Header.Serial = Source.ReadInt32();
						Header.PageNumber = Source.ReadInt32();
						Header.Checksum = Source.ReadInt32();
						Header.Segments = Source.ReadByte();
						Header.LacingValues = Source.ReadBytes(0xFF);
						return Header.AbsolutePosition;
					}
				}
			}
			return result;
		}
Пример #8
0
 public static void Write(this BinaryWriter writer, OggHeader oggHeader)
 {
     oggHeader.Write(writer);
 }