Exemplo n.º 1
0
        public void WriteParagraph(Paragraph p, Bitmap bmp, ContentAlignment alignment, Point?overridePosition = null)  // inspired by code from SubtitleCreator
        {
            // timestamp: 00:00:33:900, filepos: 000000000
            _idx.AppendLine($"timestamp: {p.StartTime.Hours:00}:{p.StartTime.Minutes:00}:{p.StartTime.Seconds:00}:{p.StartTime.Milliseconds:000}, filepos: {_subFile.Position.ToString("X").PadLeft(9, '0').ToLowerInvariant()}");

            var nbmp = new NikseBitmap(bmp);

            _emphasis2 = nbmp.ConvertToFourColors(_background, _pattern, _emphasis1, _useInnerAntiAliasing);
            var twoPartBuffer = nbmp.RunLengthEncodeForDvd(_background, _pattern, _emphasis1, _emphasis2);
            var imageBuffer   = GetSubImageBuffer(twoPartBuffer, nbmp, p, alignment, overridePosition);

            int  bufferIndex = 0;
            byte vobSubId    = (byte)_languageStreamId;
            var  mwsub       = new MemWriter(200000);

            byte[] subHeader = new byte[30];
            byte[] ts        = new byte[4];

            // Lent from "Son2VobSub" by Alain Vielle and Petr Vyskocil
            // And also from Sup2VobSub by Emmel
            subHeader[0]  = 0x00; // MPEG 2 PACK HEADER
            subHeader[1]  = 0x00;
            subHeader[2]  = 0x01;
            subHeader[3]  = 0xba;
            subHeader[4]  = 0x44;
            subHeader[5]  = 0x02;
            subHeader[6]  = 0xc4;
            subHeader[7]  = 0x82;
            subHeader[8]  = 0x04;
            subHeader[9]  = 0xa9;
            subHeader[10] = 0x01;
            subHeader[11] = 0x89;
            subHeader[12] = 0xc3;
            subHeader[13] = 0xf8;

            subHeader[14] = 0x00; // PES
            subHeader[15] = 0x00;
            subHeader[16] = 0x01;
            subHeader[17] = 0xbd;

            int  packetSize = imageBuffer.Length;
            long toWrite    = packetSize; // Image buffer + control sequence length
            bool header0    = true;

            while (toWrite > 0)
            {
                long headerSize;
                if (header0)
                {
                    header0 = false;

                    // This is only for first packet
                    subHeader[20] = 0x81;   // mark as original
                    subHeader[21] = 0x80;   // first packet: PTS
                    subHeader[22] = 0x05;   // PES header data length

                    // PTS (90kHz):
                    //--------------
                    subHeader[23] = (byte)((ts[3] & 0xc0) >> 5 | 0x21);
                    subHeader[24] = (byte)((ts[3] & 0x3f) << 2 | (ts[2] & 0xc0) >> 6);
                    subHeader[25] = (byte)((ts[2] & 0x3f) << 2 | (ts[1] & 0x80) >> 6 | 0x01);
                    subHeader[26] = (byte)((ts[1] & 0x7f) << 1 | (ts[0] & 0x80) >> 7);
                    subHeader[27] = (byte)((ts[0] & 0x7f) << 1 | 0x01);

                    const string pre             = "0010"; // 0011 or 0010 ? (KMPlayer will not understand 0011!!!)
                    long         newPts          = (long)(p.StartTime.TotalSeconds * 90000.0);
                    string       bString         = Convert.ToString(newPts, 2).PadLeft(33, '0');
                    string       fiveBytesString = pre + bString.Substring(0, 3) + "1" + bString.Substring(3, 15) + "1" + bString.Substring(18, 15) + "1";
                    for (int i = 0; i < 5; i++)
                    {
                        subHeader[23 + i] = Convert.ToByte(fiveBytesString.Substring(i * 8, 8), 2);
                    }
                    subHeader[28] = vobSubId;
                    headerSize    = 29;
                }
                else
                {
                    subHeader[20] = 0x81; // mark as original
                    subHeader[21] = 0x00; // no PTS
                    subHeader[22] = 0x00; // header data length
                    subHeader[23] = vobSubId;
                    headerSize    = 24;
                }

                if ((toWrite + headerSize) <= 0x800)
                {
                    // write whole image in one 0x800 part

                    long j = (headerSize - 20) + toWrite;
                    subHeader[18] = (byte)(j / 0x100);
                    subHeader[19] = (byte)(j % 0x100);

                    // First Write header
                    for (int x = 0; x < headerSize; x++)
                    {
                        mwsub.WriteByte(subHeader[x]);
                    }

                    // Write Image Data
                    for (int x = 0; x < toWrite; x++)
                    {
                        mwsub.WriteByte(imageBuffer[bufferIndex++]);
                    }

                    // Pad remaining space
                    long paddingSize = 0x800 - headerSize - toWrite;
                    for (int x = 0; x < paddingSize; x++)
                    {
                        mwsub.WriteByte(0xff);
                    }

                    toWrite = 0;
                }
                else
                {
                    // write multiple parts

                    long blockSize = 0x800 - headerSize;
                    long j         = (headerSize - 20) + blockSize;
                    subHeader[18] = (byte)(j / 0x100);
                    subHeader[19] = (byte)(j % 0x100);

                    // First Write header
                    for (int x = 0; x < headerSize; x++)
                    {
                        mwsub.WriteByte(subHeader[x]);
                    }

                    // Write Image Data
                    for (int x = 0; x < blockSize; x++)
                    {
                        mwsub.WriteByte(imageBuffer[bufferIndex++]);
                    }

                    toWrite -= blockSize;
                }
            }

            // Write whole memory stream to file
            long endPosition = mwsub.GetPosition();

            mwsub.GotoBegin();
            _subFile.Write(mwsub.GetBuf(), 0, (int)endPosition);
        }