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`