7

ビデオファイルをhttp経由でブラウザ(現在はChrome v24.x)に「ストリーミング」するJavaアプリケーションを作成しています。このビデオはFFmpegに送信され、この出力はHTTP経由で送信されます。

これで、ファイルが完全にエンコードされると、ファイルはチャンク転送を使用して提供され、範囲要求に応答します。ヘッダーの例:

リクエスト

GET /file/9fe6b502-c127-47c2-b6d2-83ea58676a8d HTTP/1.1 : Host: localhost:1234 : Connection: keep-alive : Accept-Encoding: identity;q=1, *;q=0 : User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17 : Accept: */* : Referer: http://localhost:1234/media/9fe6b502-c127-47c2-b6d2-83ea58676a8d : Accept-Language: en-US,en;q=0.8 : Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 : Cookie: plushContainerWidth=100%25; plushNoTopMenu=0 : Range: bytes=0- :  

応答

HTTP/1.1 206 Partial Content : Connection: close : Date: Mon, 28 Jan 2013 14:51:52 GMT : Content-Type: video/mp4 : Etag: "9fe6b502-c127-47c2-b6d2-83ea58676a8d" : Accept-Ranges: bytes : Content-Range: bytes 0-625825/625826 : Content-Length: 625826 : Transfer-Encoding: chunked :  

送信されるデータは、ヘッダーデータとチャンクオーバーヘッドを除いて、625826バイトです。

さて、これはうまくいきます!

問題は、ファイルのエンコードが完了する前にGETリクエストが発生した場合です。現在不明なため、コンテンツの長さの属性や範囲を指定せずにチャンク転送を使用して、HTTP経由でファイルの送信をすぐに開始しようとしました。これにより、ブラウザはファイル全体を待機します(転送が完了するまで再生を開始しません)。さらに、ファイル転送が完了すると、ブラウザはファイルを再生できなかったというビデオエラーを報告します。ヘッダーの例:

リクエスト

Request : GET /file/9fe6b502-c127-47c2-b6d2-83ea58676a8d HTTP/1.1 : Host: localhost:1234 : Connection: keep-alive : Accept-Encoding: identity;q=1, *;q=0 : User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17 : Accept: */* : Referer: http://localhost:1234/media/9fe6b502-c127-47c2-b6d2-83ea58676a8d : Accept-Language: en-US,en;q=0.8 : Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 : Cookie: plushContainerWidth=100%25; plushNoTopMenu=0 : Range: bytes=0- 

応答

HTTP/1.1 200 OK : Connection: close : Date: Mon, 28 Jan 2013 14:51:29 GMT : Content-Type: video/mp4 : Transfer-Encoding: chunked

送信されるデータは、ヘッダーデータとチャンクオーバーヘッドを除いて、625826バイトです。

誰かが何が悪いのか、またはファイルの完全な長さを知らずにビデオの再生を開始する方法について何か考えがありますか?

御時間ありがとうございます、

ジェームズ。

//編集

不完全なファイルのリクエストには「範囲:bytes = 0-」と記載されているため、Content-Range:bytes 0-999 / *で「n」バイト(たとえば1000バイト)の部分的なコンテンツで応答できますか?

//編集2要求に応じて、ファイルを出力するためのコードを次に示します。コードが実際には複数のクラスにまたがっているため、これは凝縮されています。

File f = new File(_filename);
RandomAccessFile raf = new RandomAccessFile(f, "r");
ChunkedOutputStream cos = new ChunkedOutputStream(_out, 1024 * 100);
byte[] bytes;

while (true){
    lBufferSizeMax = Math.min(lBufferSize, fc.length() - lCompleted);
    bytes = new byte[(int)lBufferSizeMax];

    lCurrentRead = fc.read(bytes);
    if (lCurrentRead == 0){
        break;
    }

    cos.write(bytes);
}
4

1 に答える 1

2

ffmpegは、エンコードが終了するときにファイルの一部を書き換える可能性があることに注意してください。つまり、動画ファイルのメタデータは最後まで不完全であるため、それより前にファイルの先頭をストリーミングしようとしても意味がありません。ffmpegコマンドラインの出力ファイル名を単一のダッシュに置き換えて確認し、 stdout をファイルにリダイレクトできます。ffmpeg ... out.movする代わりにffmpeg ... - > out.mov。フォーマットにシーク可能な出力が必要であるというエラー メッセージが表示された場合は、影響を受けています。

私はあなたがやろうとしていることをほぼ正確に実行しました。結果は私のGit repoにあります。メタデータを使用してゲームをプレイできるコンテナ形式は、FLV です。残念ながら、それは iPad/iPhone デバイスが好むものではありません。

于 2013-02-09T01:56:07.020 に答える