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のソースコードを分析したところ、メモリからデータを読み取ることができることがわかりました.コードは簡単です.以下に示します.
 
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;
	...
}