序文
- 前の 2 つの記事では、Gradio 出力ログと ER-NeRF 推論グラフが ts ファイルに転送されることについて説明しました。
- この記事では、サーバーによって生成された m3u8 ファイルを Gradio でリアルタイムに再生する方法について説明します。
- Web 上で再生するには、まずプレーヤー、video.js や hls.js などの hls プロトコルをサポートする Web プレーヤーが必要です。ネイティブ ビデオも再生できます。ここでは hls.js を選択します。 。
- プレーヤーに加えて、m3u8 ファイルは Web フロントエンドで見つかる必要があります。これは、gradio が URL を介した m3u8 ファイルの直接ロードをサポートできることを意味します。これには、gradio の静的ファイルのマウントが含まれます。
- また、設計した WebUI にプレーヤーを表示するには、グラデーションを有効にする必要があります。ただし、グラデーションのコンポーネント ライブラリには、hls.js スクリプトをロードできるプレーヤー コンポーネントがありません。ここでコンポーネントをカスタマイズする必要があります。
効果
- プレーヤーがロードされていないときのインターフェース:
- プレーヤーをロードした後のコンポーネント:
成し遂げる
まず、gradio が URL 経由で m3u8 静的ファイルをロードできるようにする必要があります。
この目標を達成するには、FastAPI を導入し、FastAPI を使用して静的ディレクトリをマウントし、その後 gradio で FastAPI をマウントする必要があります。
#设置静态目录
app = FastAPI()
dir = os.path.abspath(os.getcwd()) #将当前根目录作为静态目录
app.mount('/static', StaticFiles(directory=dir), 'static')
gradio と FastAPI を一緒にマウントします (現在、gradio 自体がキューをサポートする必要があります)。https://www.gradio.app/docs/mount_gradio_app を参照してください。
#将fastapi的静态目录和gradio挂载一起
page = page.queue()
app = gr.mount_gradio_app(app, page,path='/')
これを実行すると、gradio の .launch() メソッドを使用してアプリケーションを起動できなくなります。
launch() が開始された後は FastAPI 効果はなく、マウントは開始されます。無駄
ここからは Uvicorn を使用します。Uvicorn についてはオンライン情報を参照してください。
uvicorn main-webui:app --port 7861 #端口好不指定默认为8000
起動後、http://127.0.0.1/static/xx/xx/xx.m3u8 を通じてビデオ インデックス ファイルにアクセスできます。
次に、Gradio のビデオ コンポーネントをカスタマイズし、ビデオを再生させます。
ビデオの m3u8 ファイルの URL は動的に生成されるため、クライアントはサーバーのログ メッセージを聞くことしかできません。特別なメッセージが表示されると、クライアントは m3u8 アドレスが表示されたと認識します。メッセージを解析し、ビデオ インデックス ファイルの URL を取得して、再生用のビデオ コンポーネントを構築するだけです。
したがって、まず前の log_out 関数を変換し、特定のメッセージ内の m3u8 アドレスを解析させます。次に、ビデオ HTML コード文字列を Web に出力します。フロントエンド ログ解析コードがこの HTML コードを読み取った後、インターフェイス上の特定の場所にこのコードをレンダリングします。
video_div = '<div id="videoDiv" style="width:100%;height:512px;"><video style="width:100%;height:100%;" id="videoDom" controls m3u8="[M3U8URL]"></video></div>'
def log_out(new_log):
print(new_log)
if new_log.find('##M3U8##SUCCESS:')>-1:
#根据日志输出的信息处理,提取到m3u8的地址
video = new_log.replace('##M3U8##SUCCESS:', '')
video = video_div.replace('[M3U8URL]', video)
time.sleep(0.7) #让客户端有时间来出来视频显示
print('输出video:'+video)
return video
return new_log
次に、webui でログ出力関数のコードを変換します。
元のコードを参照してください: ER-NeRF/RAD-NeRF/AD-NeRF に基づいたデジタル ヒューマン生成へのインターフェイスの追加, Gradio フレームワークは WEBUI を構築し、HLS ストリーミング メディアを使用して推論と再生を実現します - 1: WEBUI でのサーバー コンソール ログのリアルタイム出力: https://blog.csdn.net/AJian759447583/article/details/133990434
_script = '''
async()=>{
.......
//将hls.js的代码加入到页面上
......
//监控日志输出及显示
let video= document.querySelector("#videoDivCom");
let output = document.querySelector("#logDivText .border-none");
if(!output){
return false;
}
let show = document.querySelector('#logShowDiv .container')
show.style.height='200px'
show.style.overflowY='scroll'
show.innerHTML=""
Object.defineProperty(output, "value", {
set: function (log) {
if(log && log!=''){
if(log.startsWith('<div id="videoDiv"')){
video.innerHTML=log
}else{
show.innerHTML = show.innerHTML+'<br>'+log
show.scrollTop=show.scrollHeight
}
}
return this.textContent = log;
}
});
......
}
'''
#在page页面加载的时候,将自定义的js加载进去
page.load(_js=_script)
このようにして、ビデオをページに動的にロードすることができ、サーバー GPU がビデオの転送中に CPU を推論し、同時に Webui クライアントがビデオを再生するという効果が得られます。
次に、このプロセスの各時点を高速化し、より優れたより高速なサーバーを使用し、リアルタイム TTS を統合すると、テキストに基づいて指定された音声をリアルタイムで生成し、指定された音声を自動的に推測するデジタル ヒューマン ビデオが作成されます。準備ができている!
もちろん、対処する必要のある詳細は 1 億件あるはずです...
上記の 3 つの記事を含め、これらは全体的な考え方の一般的な説明にすぎません。 、具体的な実装は間違いなく、対処する必要がある詳細がまだ 1 億件あります。前の 2 つの記事:
- デジタル ヒューマン生成へのインターフェイスの追加、ER-NeRF/RAD-NeRF/AD-NeRF、Gradio フレームワークに基づく WEBUI の構築、HLS ストリーミング メディアを使用した推論と再生の実現 - パート 1: WEBUI でのサーバー コンソール ログのリアルタイム出力:https://blog.csdn.net/AJian759447583/article/details/133990434
- デジタル ヒューマン生成へのインターフェイスの追加、ER-NeRF/RAD-NeRF/AD-NeRF、Gradio フレームワークに基づく WEBUI の構築、HLS ストリーミング メディアを使用した推論と再生の実現 - パート 2: ndarray メモリ シーケンス図を ts 形式ビデオに直接変換: https://blog.csdn.net/AJian759447583/article/details/133994863
要約する
- 全体的なアイデアは非常にシンプルかつ簡単で、技術的なギャップはありません。
- 細かい点で検討すべきことが多すぎて、各ステップで細かい技術的な部分に行き詰まり、さまざまな検討や試みが行われ、最終的には N 時間以上かけて解決する必要があるテスト中 - もちろんありますが、まだ解決できない可能性があります
- 今回使用されている馴染みのないテクノロジは、これまでに公開されたことがないか、馴染みのないテクノロジです。
1: サーバー ログはリアルタイムで Web クライアントに出力されます (一定の時間を費やします)。実験に多くの時間を要します)
2: Python のグラデーション フレームワーク (公式 Web サイトから学ぶことができ、簡単に始めることができます)
3: ffmpeg コマンド (非常に複雑です、私の頭では痛い...)
4: Python で ffmpeg のパイプラインを使用する (理解するのは簡単ですが、入力パイプラインが同時にパイプラインでもある場合、調査と試行に多くの時間を費やしました) 、しかし結局解決策はありませんでした)
5:Gradioのキュー、fastapi、静的ファイル(しばらく解決策を探して数時間試しました)
6: HLS ストリーミング プロトコル (スキミング)
7: m3u8 ファイル形式 (注意事項)
8: ts 形式メディア ファイルのパケット プロトコルの詳細 (ffmpeg の場合)は ts に変換されます。VLC プレーヤーには通常のオーディオとビデオがありますが、hls.js は Web) 画面でサウンドのみを再生します。この問題の解決に多くの時間を費やし、さまざまなパラメーターを試した結果、最終的に有効なパラメーターは次のとおりであると判断しました。 vcodec='libx264', r=25,output_ts_offset=ts_index * 5,hls_time=5,hls_segment_type='mpegts') - さらに最適化してほしい点: パイプライン入力とパイプライン出力には Python の ffmpeg を使用します。現在、パイプの入出力を同時に行うとプログラムがハングアップし、1フレームのデータを書き込み、1フレームのデータを読み出しても同様の現象が発生し、現在解決されていません。