FFMpeg數據流處理 抽取音視頻流

FFMpeg數據流處理

1.基本概念

(1)多媒體文件裏面其實是流的容器
(2)流有很多種比如,stream/track…但是各路流互不影響
(3)每種流是由不同的編碼器編碼的
(4)從流中解碼出的數據稱爲包
(5)在一個包中包含着一個或者多個幀

2.重要結構體

(1)AVFormatContext 上下文,連接多個api的橋樑
(2)AVStream 通過AVStream可以獲取各種包
(3)AVPacket 包中包含的就是數據幀

3.操作流的基本步驟

(1)【解複用】-【獲取流】-【讀取數據包】-【釋放資源】

4.(實戰)FFMpeg打印音頻的Meta信息

(1)API

av_register_all();
 AVFormatContext avformat_open_input();
 avformat_close_input(AVFormatContext  *);
 av_dump_format(); 
 av_err2str(ret);

(2)代碼

void handleMedia(){
	AVFormatContext* fmt_ctx = NULL; 
	int ret;
	av_register_all();
	//打開多媒體文件
	ret = avformat_open_input(&fmt_ctx,
	"./test.mp4",
	/*輸入文件格式,比如mp4*/NULL,
	/*通過命令行傳入的參數,一般不用*/NULL);
	if(ret < 0){
		av_log(NULL,AV_LOG_ERROR,"Can't open file,%s\n",av_err2str(ret));
	}else{
		av_dump_format(fmt_ctx
			,/*s索引值,一般是0*/0
			,/*文件路徑*/"./test.mp4"
			,/*輸入劉0還是輸出流1*/0);
		avformat_close_input(&fmt_ctx);
	}


}

( 3)編譯

gcc ffmpeg_media_test.c -o media_test `pkg-config --libs --cflags libavutil libavformat`

5.抽取音頻數據

(1)API

av_init_packet();
av_find_best_stream();//找到最好的一路流
av_read_frame();//讀取流中的包,注意不是幀
av_packet_unref();//與上一個api聯合使用

(3)代碼

/*
gcc ffmpeg_media_test.c -o media_test `pkg-config --libs --cflags libavutil libavformat`
*/

#include <libavformat/avformat.h>
#include <libavutil/log.h>
#include <stdio.h>

void handleMedia(char* src_path,char* dst_path);
int extractAudio(AVFormatContext* fmt_ctx,char* dst_path);

int main(int argc,char* argv[])
{
	if(argc < 3){
		av_log(NULL,AV_LOG_ERROR,"less params\n");
		return -1;
	}

	//arg[0]表示當前函數名
    char* src_path = argv[1];
    char* dst_path = argv[2];
    if(!src_path || !dst_path){
    	av_log(NULL,AV_LOG_ERROR,"path is invalid\n");
    	return -1;
    }

	handleMedia(src_path,dst_path);
	return 0;
}


void handleMedia(char* src_path,char* dst_path){
	AVFormatContext* fmt_ctx = NULL; 
	int ret;
	av_register_all();
	//打開多媒體文件
	//1.讀兩個參數從控制檯 
	ret = avformat_open_input(&fmt_ctx,
	src_path,
	/*輸入文件格式,比如mp4*/NULL,
	/*通過命令行傳入的參數,一般不用*/NULL);


	if(ret < 0){
		av_log(NULL,AV_LOG_ERROR,"Can't open file,%s\n",av_err2str(ret));
	}else{
		av_dump_format(fmt_ctx
			,/*s索引值,一般是0*/0
			,/*文件路徑*/src_path
			,/*輸入劉0還是輸出流1*/0);



		//2.獲取流
	    //3.抽取音頻數據到一個新的文件
		extractAudio(fmt_ctx,dst_path);

		avformat_close_input(&fmt_ctx);

			

	}
}


/*提取音頻到一個文件中*/
int extractAudio(AVFormatContext* fmt_ctx,char* dst_path){
	FILE* dst_file = fopen(dst_path,"wb");
	if(!dst_file){
	 	av_log(NULL,AV_LOG_ERROR,"output file create failed\n");
	 	return -1;
	}

	
	//正確返回索引值
	int	ret = av_find_best_stream(fmt_ctx,
			/*流的類型*/AVMEDIA_TYPE_AUDIO,
			/*流的索引號*/-1,
			/*流的索引號*/-1,
			/*編解碼器*/NULL,
			/*FLAG*/0);

	if(ret < 0){
		av_log(NULL,AV_LOG_ERROR,"get av_find_best_stream failed,%s\n",av_err2str(ret));
	}else{
		int audio_index = ret;
		AVPacket pkt;
		av_init_packet(&pkt);
		int length ;
		while(av_read_frame(fmt_ctx,&pkt) >= 0){
			if(pkt.stream_index == audio_index){
				fwrite(pkt.data,1,pkt.size,dst_file);
				if(length!=pkt.size){
					av_log(NULL,AV_LOG_WARNING,"size not equal pkt.size\n");
				}
			}
			av_packet_unref(&pkt);
		}

		if(dst_file){
			fclose(dst_file);
		}
		return 0;
	}


	return -1;
}

編譯

gcc ffmpeg_media_test.c -o media_test `pkg-config --libs --cflags libavutil libavformat libavcodec`
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章