0

私は自分のウェブサイトで変換中のmp3を提供しようとして、一週間ずっと頭を悩ませてきました。

とてもシンプルに見えました。

  • 私は最初に考えます:ffmpegプロセスの出力をWeb応答にリダイレクトし、次に、選択したエンコーディングが何であれ、出力が破損していることに気付きました:Windowsバージョンのffmpeg stdoutは破損したバイトを出力するだけで、そのような重要なプログラムにとっては奇妙ですが、それは本当だ。おそらく、WindowsコンソールがCP65001で出力されないという事実との非互換性です。ダンノ。

  • 次に、ffmpegによって書き込まれたファイルのコンテンツをリダイレクトしようとしましたが、ストリームの終わりに到達したこと、またはファイルのアクセス許可の問題について、多くの例外が発生しました。書き込まれているファイルの読み取りについて、SOに関する多くのスレッドを読みましたが、場合によっては、汚れの少ない別のアプローチを使用することを選択することもあります。

  • 私は、-REAL-UTF8コンテンツをstdoutに出力できるように作成されたUTFRedirect.exeと呼ばれるNeoSmartでコード化されたプログラムを使用しようとしました。そうだった。ただし、スレーブプロセスを起動する場合、このプログラムはC ++で「WaitForSingleObject」を使用しているため、非同期ではありません。コンテンツを出力する同期メソッドは役に立ちません。その場合、ファイルとそのファイルからの「ReadAllBytes」を使用するためです。

  • SoXを試してみました。stdoutエンコーディングでも同じ問題があり、URLの処理が非常に悪くなります。

  • 私は試しました:サーバー上で生成されている間にmp3をストリーミングします。しかし、それは私の問題とは似ていません。

  • ffmpeg -i input.mp3 -f mp3 - >output.mp3ffmpegで作成されたファイルに実際にアクセスできないようだったので、ffmpegでファイルへのパイプを使用してファイルを作成した場合にもっとチャンスがあるかどうかを確認しようとしました ffmpeg -i input.mp3 -f mp3 output.mp3

かつて同じ問題に直面した人はいますか?

[編集09/29]

何でもリダイレクトできるように、独自のredirect.exeプログラムを作成することにしました。私は2つのモードでそれを作りました:それはバイトをFileShare.ReadWriteファイルに書き込むか、それはそれをバイトに変換することができるように画面にHEXを出力します。

このソリューションを使用すると、ffmpegやsoxなどのstdoutのプログラムを「オンザフライ」で使用するという目標を達成できると95%確信しています。私はおそらく答えを持って戻ってきます。しかし、1つの16進数= 2バイトを表すため、このソリューションが遅いことはすでに知っています。たぶん、別の「ベース」を使用してデータを表現します。つまり、データを圧縮して、ASCIIまたはヌル文字なしで表現できるようにしますが、必要なスペースは少なくなります。

興味のある方は、標準入力から-REAL-バイトを読み取るために、次のメソッドがあります。

using (Stream stdin = Console.OpenStandardInput())
    using (Stream stdout = Console.OpenStandardOutput())
            {
                byte[] buffer = new byte[2048];
                int bytes;
                while ((bytes = stdin.Read(buffer, 0, buffer.Length)) > 0)
                {                        
                    // Now you have a buffer of bytes in 'buffer'
                }
            }                

[編集09/30]

バイトを取得できるようになったので、StandardOutputバイトをAscii85として出力します。100%ではなく25%多くのスペースが必要です。

4

1 に答える 1

0

プログラムの stdout をリダイレクトし、バイトを ascii85 として出力する C# コンソール アプリを作成しました。そのため、C# プロセスにバイトを出力する Windows シェルの容量について心配する必要はもうありません。

現在、ffmpeg で変換された MP3 から Webresponse バイトにオンザフライでリダイレクトするために使用していますが、動作します。

Ascii85 は、100% のオーバーヘッドを表す 16 進数の文字列と比較すると、バイト空間に対して 25% のオーバーヘッドを表し、base64 はデータサイズの 33% のオーバーヘッドを表します。

Jeff Atwood の Coding Horror ブログ ( http://www.codinghorror.com/blog/2005/10/c-implementation-of-ascii85.html ) にある、Jeff Atwood の Ascii85 クラスを使用しました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace stdshare {
    class Program
    {
        static void Main(string[] args)
        {

                Int32 dur = 0;
        try 
                {
                    dur = Convert.ToInt32(args[0]);
        } catch { return; }

            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

                    using (Stream stdin = Console.OpenStandardInput())
                    using (Stream stdout = Console.OpenStandardOutput())
                    {
                        byte[] buffer = new byte[2048];
                        byte[] buffer2 = new byte[2048];

                        int bytes;
                int pos = 0;
                        using (BinaryReader br = new BinaryReader(stdin))
                        while ((bytes = br.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            buffer2 = new byte[bytes];
                            Buffer.BlockCopy(buffer, 0, buffer2, 0, bytes);
                            string s = System.Convert.ToBase64String(buffer2);
                            Console.WriteLine(s);
                            Console.Out.Flush();
                            stdout.Flush();                            
                  pos += 1;
                  if (pos > dur) break;
                        }


                    }                 



        }


        class Ascii85
        {
            /// <summary>
            /// Prefix mark that identifies an encoded ASCII85 string, traditionally '<~'
            /// </summary>
            public string PrefixMark = "<~";
            /// <summary>
            /// Suffix mark that identifies an encoded ASCII85 string, traditionally '~>'
            /// </summary>
            public string SuffixMark = "~>";
            /// <summary>
            /// Maximum line length for encoded ASCII85 string; 
            /// set to zero for one unbroken line.
            /// </summary>
            public int LineLength = 0;
            /// <summary>
            /// Add the Prefix and Suffix marks when encoding, and enforce their presence for decoding
            /// </summary>
            public bool EnforceMarks = true;

            private const int _asciiOffset = 33;
            private byte[] _encodedBlock = new byte[5];
            private byte[] _decodedBlock = new byte[4];
            private uint _tuple = 0;
            private int _linePos = 0;

            private uint[] pow85 = { 85 * 85 * 85 * 85, 85 * 85 * 85, 85 * 85, 85, 1 };

            /// <summary>
            /// Decodes an ASCII85 encoded string into the original binary data
            /// </summary>
            /// <param name="s">ASCII85 encoded string</param>
            /// <returns>byte array of decoded binary data</returns>
            public byte[] Decode(string s)
            {
                if (EnforceMarks)
                {
                    if (!s.StartsWith(PrefixMark) | !s.EndsWith(SuffixMark))
                    {
                        throw new Exception("ASCII85 encoded data should begin with '" + PrefixMark +
                            "' and end with '" + SuffixMark + "' Problematic string: " + s);
                    }
                }

                // strip prefix and suffix if present
                if (s.StartsWith(PrefixMark))
                {
                    s = s.Substring(PrefixMark.Length);
                }
                if (s.EndsWith(SuffixMark))
                {
                    s = s.Substring(0, s.Length - SuffixMark.Length);
                }

                MemoryStream ms = new MemoryStream();
                int count = 0;
                bool processChar = false;

                foreach (char c in s)
                {
                    switch (c)
                    {
                        case 'z':
                            if (count != 0)
                            {
                                throw new Exception("The character 'z' is invalid inside an ASCII85 block.");
                            }
                            _decodedBlock[0] = 0;
                            _decodedBlock[1] = 0;
                            _decodedBlock[2] = 0;
                            _decodedBlock[3] = 0;
                            ms.Write(_decodedBlock, 0, _decodedBlock.Length);
                            processChar = false;
                            break;
                        case '\n':
                        case '\r':
                        case '\t':
                        case '\0':
                        case '\f':
                        case '\b':
                            processChar = false;
                            break;
                        default:
                            if (c < '!' || c > 'u')
                            {
                                throw new Exception("Bad character '" + c + "' found. ASCII85 only allows characters '!' to 'u'.");
                            }
                            processChar = true;
                            break;
                    }

                    if (processChar)
                    {
                        _tuple += ((uint)(c - _asciiOffset) * pow85[count]);
                        count++;
                        if (count == _encodedBlock.Length)
                        {
                            DecodeBlock();
                            ms.Write(_decodedBlock, 0, _decodedBlock.Length);
                            _tuple = 0;
                            count = 0;
                        }
                    }
                }

                // if we have some bytes left over at the end..
                if (count != 0)
                {
                    if (count == 1)
                    {
                        throw new Exception("The last block of ASCII85 data cannot be a single byte.");
                    }
                    count--;
                    _tuple += pow85[count];
                    DecodeBlock(count);
                    for (int i = 0; i < count; i++)
                    {
                        ms.WriteByte(_decodedBlock[i]);
                    }
                }

                return ms.ToArray();
            }

            /// <summary>
            /// Encodes binary data into a plaintext ASCII85 format string
            /// </summary>
            /// <param name="ba">binary data to encode</param>
            /// <returns>ASCII85 encoded string</returns>
            public string Encode(byte[] ba)
            {
                StringBuilder sb = new StringBuilder((int)(ba.Length * (_encodedBlock.Length / _decodedBlock.Length)));
                _linePos = 0;

                if (EnforceMarks)
                {
                    AppendString(sb, PrefixMark);
                }

                int count = 0;
                _tuple = 0;
                foreach (byte b in ba)
                {
                    if (count >= _decodedBlock.Length - 1)
                    {
                        _tuple |= b;
                        if (_tuple == 0)
                        {
                            AppendChar(sb, 'z');
                        }
                        else
                        {
                            EncodeBlock(sb);
                        }
                        _tuple = 0;
                        count = 0;
                    }
                    else
                    {
                        _tuple |= (uint)(b << (24 - (count * 8)));
                        count++;
                    }
                }

                // if we have some bytes left over at the end..
                if (count > 0)
                {
                    EncodeBlock(count + 1, sb);
                }

                if (EnforceMarks)
                {
                    AppendString(sb, SuffixMark);
                }
                return sb.ToString();
            }

            private void EncodeBlock(StringBuilder sb)
            {
                EncodeBlock(_encodedBlock.Length, sb);
            }

            private void EncodeBlock(int count, StringBuilder sb)
            {
                for (int i = _encodedBlock.Length - 1; i >= 0; i--)
                {
                    _encodedBlock[i] = (byte)((_tuple % 85) + _asciiOffset);
                    _tuple /= 85;
                }

                for (int i = 0; i < count; i++)
                {
                    char c = (char)_encodedBlock[i];
                    AppendChar(sb, c);
                }

            }

            private void DecodeBlock()
            {
                DecodeBlock(_decodedBlock.Length);
            }

            private void DecodeBlock(int bytes)
            {
                for (int i = 0; i < bytes; i++)
                {
                    _decodedBlock[i] = (byte)(_tuple >> 24 - (i * 8));
                }
            }

            private void AppendString(StringBuilder sb, string s)
            {
                if (LineLength > 0 && (_linePos + s.Length > LineLength))
                {
                    _linePos = 0;
                    sb.Append('\n');
                }
                else
                {
                    _linePos += s.Length;
                }
                sb.Append(s);
            }

            private void AppendChar(StringBuilder sb, char c)
            {
                sb.Append(c);
                _linePos++;
                if (LineLength > 0 && (_linePos >= LineLength))
                {
                    _linePos = 0;
                    sb.Append('\n');
                }
            }

        }
    }
}
于 2012-10-05T05:25:34.197 に答える