ffmpegメモリからデータを読み出す(またはメモリに出力する)
3583 ワード
更新記録(2014.7.24):
1.本明細書をより分かりやすくするために、一部の内容を更新し、例をメモリから開くように変更しました.
2.メモリにデータを出力する方法を追加しました.
メモリからデータを読み込む
ffmpegは一般的に「C:test.avi」などのローカルファイルを開くことをサポートします.
あるいは、ストリーミングメディアプロトコルのURL、例えば「rtmp://222.31.64.208/vod/test.flv”
ファイルを開く関数はavformat_です.open_Input()は,ファイルパスやストリーミングメディアURLの文字列を直接この関数に渡せばよい.
しかし、メモリからのデータの読み取りはサポートされていますか?この問題は長い間困っていた.当時プロジェクトをしていた頃、Winpcapでネットワーク上のRTPパケットをキャプチャし、ffmpegに直接送って復号しようとした.なかなか適当な方法が見つからなかった.キャプチャされたパケットはメモリに存在するため、avformat_に渡すことができません.open_input()関数はそのパス(パス===がまったくありません).もちろん、キャプチャしたデータをファイルにレポートしてffmpegで開くこともできますが、これではプログラムの制御が難しくなります.
その後ffmpegのソースコードを分析したところ、メモリからデータを読み取ることができることがわかりました.コードは簡単です.以下に示します.
重要なのはavformat_open_input()の前にAVIOContextを初期化し、元のAVFormatContextのポインタpb(AVIOContextタイプ)をこれに向けてAVIOContextを自己初期化します.AVIOContextを自己指定すると、avformat_open_input()内のURLパラメータは機能しません.サンプルコードは、AVIOContextのキャッシュとして空間iobufferを開きます.
fill_iobufferは、iobufferにデータを読み込むコールバック関数です.fill_iobuffer()形式(パラメータ、戻り値)は固定され、次のようにコールバック関数です(例にすぎませんが、データをどのように読み取るかは自分で設計できます).例では、コールバック関数はファイルの内容をfread()を介してメモリに読み込みます.
全体の構造は大体以下の通りである.
メモリへのデータの出力
ffmpegは、メモリからデータを読み出すのと同様に、処理後のデータをメモリに出力することもできます.
コールバック関数は、メモリに出力されたデータをファイルに書き込む例です.
主関数は以下のようになり、AVIOContextを初期化する.
1.本明細書をより分かりやすくするために、一部の内容を更新し、例をメモリから開くように変更しました.
2.メモリにデータを出力する方法を追加しました.
メモリからデータを読み込む
ffmpegは一般的に「C:test.avi」などのローカルファイルを開くことをサポートします.
あるいは、ストリーミングメディアプロトコルのURL、例えば「rtmp://222.31.64.208/vod/test.flv”
ファイルを開く関数はavformat_です.open_Input()は,ファイルパスやストリーミングメディアURLの文字列を直接この関数に渡せばよい.
しかし、メモリからのデータの読み取りはサポートされていますか?この問題は長い間困っていた.当時プロジェクトをしていた頃、Winpcapでネットワーク上のRTPパケットをキャプチャし、ffmpegに直接送って復号しようとした.なかなか適当な方法が見つからなかった.キャプチャされたパケットはメモリに存在するため、avformat_に渡すことができません.open_input()関数はそのパス(パス===がまったくありません).もちろん、キャプチャしたデータをファイルにレポートしてffmpegで開くこともできますが、これではプログラムの制御が難しくなります.
その後ffmpegのソースコードを分析したところ、メモリからデータを読み取ることができることがわかりました.コードは簡単です.以下に示します.
AVFormatContext *ic = NULL;
ic = avformat_alloc_context();
unsigned char * iobuffer=(unsigned char *)av_malloc(32768);
AVIOContext *avio =avio_alloc_context(iobuffer, 32768,0,NULL,fill_iobuffer,NULL,NULL);
ic->pb=avio;
err = avformat_open_input(&ic, "nothing", NULL, NULL);
重要なのはavformat_open_input()の前にAVIOContextを初期化し、元のAVFormatContextのポインタpb(AVIOContextタイプ)をこれに向けてAVIOContextを自己初期化します.AVIOContextを自己指定すると、avformat_open_input()内のURLパラメータは機能しません.サンプルコードは、AVIOContextのキャッシュとして空間iobufferを開きます.
fill_iobufferは、iobufferにデータを読み込むコールバック関数です.fill_iobuffer()形式(パラメータ、戻り値)は固定され、次のようにコールバック関数です(例にすぎませんが、データをどのように読み取るかは自分で設計できます).例では、コールバック関数はファイルの内容をfread()を介してメモリに読み込みます.
// -------------------------
//AVIOContext !
// :
// AVIOContext : buffer, Buffer FFmpeg
int fill_iobuffer(void * buffer,uint8_t *iobuf, int bufsize){
if(!feof(fp_open)){
int true_size=fread(buf,1,buf_size,fp_open);
return true_size;
}else{
return -1;
}
}
全体の構造は大体以下の通りである.
FILE *fp_open;
int fill_iobuffer(void * buffer,uint8_t *iobuf, int bufsize){
...
}
int main(){
...
fp_open=fopen("test.h264","rb+");
AVFormatContext *ic = NULL;
ic = avformat_alloc_context();
unsigned char * iobuffer=(unsigned char *)av_malloc(32768);
AVIOContext *avio =avio_alloc_context(iobuffer, 32768,0,NULL,fill_iobuffer,NULL,NULL);
ic->pb=avio;
err = avformat_open_input(&ic, "nothing", NULL, NULL);
...//
}
メモリへのデータの出力
ffmpegは、メモリからデータを読み出すのと同様に、処理後のデータをメモリに出力することもできます.
コールバック関数は、メモリに出力されたデータをファイルに書き込む例です.
//
int write_buffer(void *opaque, uint8_t *buf, int buf_size){
if(!feof(fp_write)){
int true_size=fwrite(buf,1,buf_size,fp_write);
return true_size;
}else{
return -1;
}
}
主関数は以下のようになり、AVIOContextを初期化する.
FILE *fp_write;
int write_buffer(void *opaque, uint8_t *buf, int buf_size){
...
}
main(){
...
fp_write=fopen("src01.h264","wb+"); //
...
AVFormatContext* ofmt_ctx=NULL;
avformat_alloc_output_context2(&ofmt_ctx, NULL, "h264", NULL);
unsigned char* outbuffer=(unsigned char*)av_malloc(32768);
AVIOContext *avio_out =avio_alloc_context(outbuffer, 32768,0,NULL,NULL,write_buffer,NULL);
ofmt_ctx->pb=avio_out;
ofmt_ctx->flags=AVFMT_FLAG_CUSTOM_IO;
...
}