最近、JavacvのFFMPEGパッケージを使用したFFMPEGFrameGrabberフレームのキャプターは、キャプチャされたオーディオフレームとビデオフレームを同期しました。使用される同期方法は、ビデオをオーディオに同期することです。
プログラムとソースコード
具体的なアイデアは次のとおりです。
(1)最初にFFMPEGがビデオファイルの画像とサウンドをキャプチャする方法を紹介する
ffmpegframegrabber fg = new ffmpegframegrabber( "ビデオファイルパスまたはURL);
フレームキャプチャオブジェクトを取得した後、grab()メソッドを呼び出すと、キャプチャされたフレームオブジェクトが返されます。このフレームは、タイムスタンプに応じて再生時間に最初に配置されるため、ビデオフレームまたはオーディオフレームにすることができます。もちろん、キャプチャされたフレームはすべてjava.nio.bufferオブジェクトにデコードされ、保存されます。ビデオフレームの場合、バッファはRGBなどの画像のピクセルデータを保存してから渡すことです。
bufferedimage bi =(new Java2DFrameConverter())。getBufferedImage(f);
写真を入手でき、取得した画像は一連のプロセスで処理したり、処理せずにスイングコンポーネントに直接表示したりできます。オーディオフレームに対応すると、バッファはオーディオを保存するPCMデータです。このPCMはフロートまたはショートにすることができ、その後、java.sounds.soundsのsourcedataline.writeメソッドを使用して、これらのオーディオPCMデータをスピーカーに書き込むことができます。
(2)次に、取得したフレームを継続的に再生する方法を紹介します。まず、ビデオを個別に再生します。
while(true){frame f = fg.grab(); if(f.image!= null)label.seticon(new ImageIcon((new Java2DFrameConverter())。GetBufferEdimage(f))); thread.sleep(1000/ビデオフレームレート); }同じことがオーディオを個別に再生することにも当てはまります。サウンドカードにデータを書き込むだけです。例
(3)生産および消費者モデル。
上記の写真は、プログラムによって実装された方法です。キャプチャされたフレームは、プロデューサーモードを使用して審査されます。ビデオフレームの場合、ビデオFIFOに作成されます。オーディオフレームの場合、オーディオFIFOに生成されます。次に、オーディオ再生スレッドとビデオ再生スレッドは、それぞれのフレームウェアハウスからそれぞれフレームを消費します。フレームキャプチャの速度がフレームの消費よりも大きいため、生産消費者モードが採用されているため、バッファリングのためにフレームをキャプチャするか、キャプチャされたフレームをさらに前処理することを好みますが、ビデオとオーディオの再生スレッドは、処理されたフレームを直接再生して表示する必要があります。
(4)オーディオとビデオの同期を実現する方法:すべてのビデオフレームを2つのオーディオフレームで再生します。
オーディオとビデオの同期を実現するには、フレームタイムスタンプが必要です。ここでキャプチャされたフレームは再生タイムスタンプPTSのみであり、デコードされたタイムスタンプDTSはないため、再生タイムスタンプに基づいて再生タイムスタンプを決定する必要があります。
プログラムの実装は、上記の図に基づいています。オーディオスレッドがオーディオフレームA1の再生を開始すると、ビデオスレッドのSetRunメソッドが呼び出され、オーディオフレームのタイムスタンプカータイムと次のフレームオーディオフレームA2の次のタイムスタンプが待機状態のビデオスレッドに渡されます。次に、ビデオスレッドが起動し、ビデオFIFOからビデオフレームG1を取り出して開始し、再生遅延としてG1とA1の時差を計算します。 swrep.sleep(t1)の後、ビデオスレッドは、jlabel.seticon(画像)などのスイングコンポーネントに画像を表示します。次に、ビデオスレッドは画像G2の別のフレームを取り出し、G2のタイムスタンプをA2のタイムスタンプと比較します。 G2のタイムスタンプがA2未満の場合、ビデオスレッドは引き続きT2を遅らせ、G2画像を再生します。 G3は、G4が取得され、A2がA2と比較され、G4のタイムスタンプがA2よりも大きいことがわかり、ビデオスレッドが待機状態に入り、次のスタートアップを待つことがわかります。次に、オーディオスレッドがA1オーディオフレームを再生した後、ウェアハウスからオーディオフレームA3を取り出し、A2のタイムスタンプとA3のタイムスタンプをビデオスレッドに渡し、A2の再生を開始し、ブロックされたビデオスレッドが再生され続けます。
(5)遅延時間を動的に調整します
個人のPCはリアルタイムオペレーティングシステムではないため、スレッド。スリープは不正確であり、サウンドカードによってサウンドを再生するために制限されているため、上記の基本的な実装のアイデアを改善する必要があります。まず、Java Sourcedatalineメソッドは、特定の速度で内部バッファーからオーディオスレッドによって記述されたデータを抽出することです。オーディオによって記述されたデータが削除された場合、オーディオ再生はutter音を立てます。ただし、オーディオデータが一度に記述されている場合、オーディオとビデオは同期していない可能性があります。したがって、Sourcedatalineの内部バッファーに特定のデータがあることを確認する必要があります。そうしないと、遅延が発生しますが、データの量はそれほど多くありません。したがって、G3からA2へのサウンド再生を調整します。遅延の不正確さにより、A1フレームで記述されたデータは、時間がT6に達する前にサウンドカードによって削除される場合があります。したがって、G3画像を再生した後、サウンドスレッドはSourcedataline.abailable()によって返されるデータの量に基づいて判断します。データの量が終了しようとしている場合、G3からA2への遅延時間T4が減少します。これにより、データボリュームが0に変化しないようにし、音声がst音を発生させます。
(6)以下は、Windows 64およびUbuntu14に基づくプログラムのテストの結果図です。再生は比較的スムーズであり、同期も可能ですが、再生がオンになると、PenguinがIDEなどのIDEでコードを書き込むと止まります。結局のところ、IdeaはJavaでも開発されているため、アイデアの操作は他のJavaプログラムに影響しますが、他のプロセスは影響しません。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。