示例#1
0
        private OggPage GetOggPage(ref int offset)
        {
            OggPageHeader hdr      = new OggPageHeader();
            OggPage       page     = new OggPage();
            int           pageSize = 0;

            ByteArrayToStructure(Audio, offset, ref hdr);

            if (hdr.Header[0] != 'O' || hdr.Header[1] != 'g' || hdr.Header[2] != 'g' || hdr.Header[3] != 'S')
            {
                return(null);
            }

            page.Header = hdr;
            pageSize   += Marshal.SizeOf(hdr);

            page.Segments = new byte[0][];

            /* where will the segment data start */
            int segmentDataPos = pageSize + hdr.PageSegments;
            /* position in page segment table */
            int pageSegTablePos = 0;
            /* logical number of the segment */
            int pageSegNum = 0;

            while (pageSegTablePos < hdr.PageSegments)
            {
                int lenEntry = Audio[offset + pageSize];
                int len      = lenEntry;
                pageSize++;
                pageSegTablePos++;

                while (lenEntry == 0xFF)
                {
                    lenEntry = Audio[offset + pageSize];
                    len     += lenEntry;
                    pageSize++;
                    pageSegTablePos++;
                }
                Array.Resize(ref page.Segments, pageSegNum + 1);
                page.Segments[pageSegNum] = new byte[len];
                Array.Copy(Audio, offset + segmentDataPos, page.Segments[pageSegNum], 0, len);
                segmentDataPos += page.Segments[pageSegNum].Length;
                pageSegNum++;
            }

            page.Size = segmentDataPos;
            offset   += segmentDataPos;

            return(page);
        }
示例#2
0
        private void _LoadOggPages(string _path)
        {
            FileStream stream = new FileStream(_path, FileMode.Open);

            long pos = 0;
            long end = stream.Length;

            Bunch <OggPage> ps = new Bunch <OggPage>();

            while (pos < end)
            {
                byte[] header = new byte[27];
                stream.Read(header, 0, 27);

                OggPage p = new OggPage();
                p.Granule        = Beth.FromEndian(header.SubArray(6, 8));
                p.StreamId       = (int)Beth.FromEndian(header.SubArray(14, 4));
                p.StreamPosition = (int)Beth.FromEndian(header.SubArray(18, 4));

                int ss = header[26];
                p.Segments = new byte[ss];
                pos       += 27;

                int si = 0;
                while (ss > 0)
                {
                    ss--;
                    p.Segments[si] = ((byte)stream.ReadByte());
                    si++;
                    pos++;
                }

                p.SegmentsPositionInFile = pos;

                foreach (byte s in p.Segments)
                {
                    pos             += s;
                    stream.Position += s;
                }

                ps.Add(p);
            }

            stream.Close();

            byte[][] bs1 = ps[0].ReadSegments(_path);
            byte[][] bs2 = ps[1].ReadSegments(_path);

            throw new Exception();
        }
示例#3
0
        public void Encode(OggStreamState oggStreamState, VorbisBlock block, Stream stream)
        {
            OggPacket packet = new OggPacket();
            OggPage   page   = new OggPage();

            /* vorbis does some data preanalysis, then divvies up blocks for
             * more involved (potentially parallel) processing.  Get a single
             * block for encoding now */
            while (BlockOut(block))
            {
                /* analysis, assume we want to use bitrate management */
                block.Analyze();
                block.BitrateAddBlock();

                while (BitrateFlushPacket(packet) != 0)
                {
                    /* weld the packet into the bitstream */
                    NativeMethods.ogg_stream_packetin(ref oggStreamState.InternalStruct, ref packet.InternalStruct);

                    /* write out pages (if any) */
                    bool eos = false;
                    while (!eos)
                    {
                        int result = NativeMethods.ogg_stream_pageout(ref oggStreamState.InternalStruct, ref og);
                        if (result == 0)
                        {
                            break;
                        }
                        page.Write(stream);

                        /* this could be set above, but for illustrative purposes, I do
                         * it here (to show that vorbis does know where the stream ends) */

                        if (xm.ogg_page_eos(ref page.InternalStruct) != 0)
                        {
                            eos = true;
                        }
                    }
                }
            }
        }
示例#4
0
 private static bool IsMetaType(OggPage header, string type)
 {
     return(Encoding.UTF8.GetString(header.Segments[0], 0, 8) == type);
 }
示例#5
0
        public void DumpAudioFiles(string outDirectory, string outFileName, bool singleOgg, string[] tags, string[] titles)
        {
            int hdrOffset = 0;

            OggPage[] metaPages = GetOggHeaders(ref hdrOffset);
            AddTags(metaPages, tags);

            if (singleOgg)
            {
                string outFile = Path.Combine(outDirectory, outFileName);

                File.WriteAllBytes(outFile + ".ogg", Audio);
                //File.WriteAllText(outFile + ".cue", BuildCueSheet(tonie), Encoding.UTF8);
            }
            else
            {
                for (int chapter = 0; chapter < Header.AudioChapters.Length; chapter++)
                {
                    string     fileName       = Path.Combine(outDirectory, outFileName + " - Track #" + (chapter + 1) + ".ogg");
                    FileStream outFile        = File.Open(fileName, FileMode.Create, FileAccess.Write);
                    OggPage[]  metaPagesTrack = metaPages.Select(p => new OggPage(p)).ToArray();

                    if (titles != null && chapter < titles.Length)
                    {
                        string[] trackTags = new[] { "TITLE=" + titles[chapter] };
                        AddTags(metaPagesTrack, trackTags);
                    }

                    foreach (OggPage page in metaPagesTrack)
                    {
                        page.Write(outFile);
                    }

                    int offset    = Math.Max(0, (int)(0x1000 * (Header.AudioChapters[chapter] - 2)));
                    int endOffset = int.MaxValue;

                    if (chapter + 1 < Header.AudioChapters.Length)
                    {
                        endOffset = Math.Max(0, (int)(0x1000 * (Header.AudioChapters[chapter + 1] - 2)));
                    }

                    bool  done         = false;
                    ulong granuleStart = ulong.MaxValue;
                    uint  pageStart    = uint.MaxValue;
                    while (!done)
                    {
                        OggPage page = GetOggPage(ref offset);

                        if (page == null)
                        {
                            break;
                        }

                        /* reached the end of this chapter? */
                        if (offset >= endOffset || offset >= Audio.Length)
                        {
                            /* set EOS flag */
                            page.Header.Type = 4;
                            done             = true;
                        }

                        /* do not write meta headers again. only applies to first chapter */
                        if (!IsMeta(page))
                        {
                            /* set granule position relative to chapter start */
                            if (granuleStart == ulong.MaxValue)
                            {
                                granuleStart = page.Header.GranulePosition;
                                pageStart    = page.Header.PageSequenceNumber;
                            }

                            page.Header.GranulePosition    -= granuleStart;
                            page.Header.PageSequenceNumber -= pageStart;
                            page.Header.PageSequenceNumber += 2;


                            page.Write(outFile);
                        }
                    }

                    outFile.Close();
                }
            }
        }
示例#6
0
    public static void WriteFile(Unity_Studio.EndianStream stream, string file, int offset, int size, Ogg ogg)
    {
        // Write to disk
        using (BinaryWriter writer = new BinaryWriter(File.Open(file, FileMode.Create)))
        {
            // Only support header CRC 3605052372 for now
            OggVorbisHeader head = new OggVorbisHeader();

            HeaderPacketBuilder hpb    = new HeaderPacketBuilder();
            CodecSetup          cSetup = new CodecSetup(null);
            cSetup.BlockSizes[0] = 256;
            cSetup.BlockSizes[1] = 2048;

            VorbisInfo info = new VorbisInfo(cSetup, (int)ogg.channels, (int)ogg.frequency, 0);

            OggPacket headerInfo = hpb.BuildInfoPacket(info);

            Comments comments = new Comments();
            if (ogg.loopStart > 0 && ogg.loopEnd > 0)
            {
                comments.AddTag("LOOP_START", ogg.loopStart.ToString());
                comments.AddTag("LOOP_END", ogg.loopEnd.ToString());
            }
            OggPacket headerComment = hpb.BuildCommentsPacket(comments);
            OggPacket headerSetup   = new OggPacket(OggVorbisHeader.GetHeader(ogg.crc32), false, 0, 2);

            OggStream output = new OggStream(1);
            output.PacketIn(headerInfo);
            output.PacketIn(headerComment);
            output.PacketIn(headerSetup);

            stream.Position = offset;

            UInt16 packetSize     = stream.ReadUInt16();
            int    prevPacketNo   = 2;
            int    prevGranulePos = 0;

            while (packetSize > 0)
            {
                OggPacket packet = new OggPacket(stream.ReadBytes(packetSize), false, 0, prevPacketNo + 1);

                byte firstByte = packet.PacketData[0];

                // OK for stereo
                int granuleSize = 128;
                if ((firstByte & 2) != 0)
                {
                    granuleSize = 1024;
                }

                if (ogg.channels == 1)
                {
                    granuleSize /= 4;
                }
                packet.GranulePosition = prevGranulePos + granuleSize;

                if (stream.Position + 2 < offset + size)
                {
                    packetSize = stream.ReadUInt16();
                }
                else
                {
                    packetSize = 0;
                }
                packet.EndOfStream = packetSize == 0;
                prevGranulePos     = packet.GranulePosition;
                prevPacketNo       = packet.PacketNumber;

                output.PacketIn(packet);
                OggPage page = null;
                if (output.PageOut(out page, true))
                {
                    writer.Write(page.Header);
                    writer.Write(page.Body);
                }
            }

            //float vorbis_quality = ((ogg.quality - 1) + (ogg.quality - 100) * 0.1f) / 99.0f;
            //VorbisInfo.InitVariableBitRate(ogg.channels, ogg.frequency, ogg.)
            //writer.Write();
            writer.Close();
        }
    }
    /// <summary>
    /// </summary>
    /// <param name="page">The output data (if any)</param>
    /// <param name="force">A value indicating whether an unfinished page should be pushed out</param>
    /// <returns>A value indicating whether data was output</returns>
    public bool PageOut(out OggPage page, bool force)
    {
        const int bufferSize = 4096;

        var  acc             = 0;
        long granulePosition = -1;

        page = null;

        var maxValues = _lacingFill > 255 ? 255 : _lacingFill;

        if (maxValues == 0)
        {
            return(false);
        }

        int vals;

        // construct a page - decide how many segments to include
        // If this is the initial header case, the first page must only include the initial header packet
        if (!_writesHaveStarted)
        {
            // 'initial header page' case
            granulePosition = 0;
            for (vals = 0; vals < maxValues; vals++)
            {
                if ((_lacingValues[vals] & 0x0ff) < 255)
                {
                    vals++;
                    break;
                }
            }
        }
        else
        {
            // The extra packets_done, packet_just_done logic here attempts to do two things:
            //  1) Don't unnecessarily span pages.
            //  2) Unless necessary, don't flush pages if there are less than four packets on
            //     them; this expands page size to reduce unnecessarily overhead if incoming packets
            //     are large.
            //  These are not necessary behaviors, just 'always better than naive flushing'
            //  without requiring an application to explicitly request a specific optimized
            //  behavior. We'll want an explicit behavior setup pathway eventually as well.
            var packetsDone     = 0;
            var packetsJustDone = 0;
            for (vals = 0; vals < maxValues; vals++)
            {
                if ((acc > bufferSize) && (packetsJustDone >= 4))
                {
                    force = true;
                    break;
                }

                acc += _lacingValues[vals] & 0x0ff;
                if ((_lacingValues[vals] & 0xff) < 255)
                {
                    granulePosition = _granuleValues[vals];
                    packetsJustDone = ++packetsDone;
                }
                else
                {
                    packetsJustDone = 0;
                }
            }

            if (vals == 255)
            {
                force = true;
            }
        }

        if (!force)
        {
            return(false);
        }

        var packetHeader = new byte[vals + 27];

        // construct the header in temp storage
        const string headerOggs = "OggS";

        for (var i = 0; i < headerOggs.Length; ++i)
        {
            packetHeader[i] = (byte)headerOggs[i];
        }

        // stream structure version
        packetHeader[4] = 0x00;

        // continued packet flag?
        packetHeader[5] = 0x00;
        if ((_lacingValues[0] & 0x100) == 0)
        {
            packetHeader[5] |= 0x01;
        }

        // first page flag?
        if (!_writesHaveStarted)
        {
            packetHeader[5] |= 0x02;
        }

        // last page flag?
        if (Finished && (_lacingFill == vals))
        {
            packetHeader[5] |= 0x04;
        }

        _writesHaveStarted = true;

        // 64 bits of PCM position
        for (var i = 6; i < 14; i++)
        {
            packetHeader[i]   = (byte)(granulePosition & 0xff);
            granulePosition >>= 8;
        }

        // 32 bits of stream serial number
        var serialno = _serialNumber;

        for (var i = 14; i < 18; i++)
        {
            packetHeader[i] = (byte)(serialno & 0xff);
            serialno      >>= 8;
        }

        // 32 bits of page counter (we have both counter and page header
        // because this val can roll over)
        if (_pageNumber == -1)
        {
            _pageNumber = 0;
        }

        var pageno = _pageNumber++;

        for (var i = 18; i < 22; i++)
        {
            packetHeader[i] = (byte)(pageno & 0xff);
            pageno        >>= 8;
        }

        // zero for computation; filled in later
        packetHeader[22] = 0;
        packetHeader[23] = 0;
        packetHeader[24] = 0;
        packetHeader[25] = 0;

        // segment table
        var bytes = 0;

        packetHeader[26] = (byte)(vals & 0xff);
        for (var i = 0; i < vals; i++)
        {
            bytes += packetHeader[i + 27] = (byte)(_lacingValues[i] & 0xff);
        }

        var packetBody = new byte[bytes];

        Array.Copy(_bodyData, _bodyReturned, packetBody, 0, bytes);

        uint crcReg = 0;

        // calculate the checksum
        foreach (var h in packetHeader)
        {
            crcReg = (crcReg << 8) ^ Checksum[(int)(((crcReg >> 24) & 0xff) ^ h)];
        }

        foreach (var b in packetBody)
        {
            crcReg = (crcReg << 8) ^ Checksum[(int)(((crcReg >> 24) & 0xff) ^ b)];
        }

        packetHeader[22] = (byte)(crcReg & 0xff);
        packetHeader[23] = (byte)((crcReg >> 8) & 0xff);
        packetHeader[24] = (byte)((crcReg >> 16) & 0xff);
        packetHeader[25] = (byte)((crcReg >> 24) & 0xff);

        // Create the page
        page = new OggPage(packetHeader, packetBody);

        // advance the lacing data and set the body_returned pointer
        _lacingFill -= vals;
        Array.Copy(_lacingValues, vals, _lacingValues, 0, _lacingFill);
        Array.Copy(_granuleValues, vals, _granuleValues, 0, _lacingFill);
        _bodyReturned += bytes;

        return(true);
    }