FFmpeg使用流程

93 篇文章 52 订阅

一、FFMPeg一般流程:

1、av_register_all();//注册所有文件格式和编解码库

2、avformat_network_init();//打开网络视频流

3、av_open_input_file();//读取文件头部把信息保存到AVFormatContext结构体

4、av_find_stream_info();//为pFormatCtx->streams填充上正确的信息

5、CODEC_TYPE_VIDEO;//通过判断得到视频流类型

6、avcodec_find_decoder();//查找解码器

7、avcodec_open();//打开编解码器

8、avcodec_alloc_frame();//分配空间保存帧数据

9、av_read_frame();//不断从流中提取帧数据

10、avcodec_decode_video();//解码视频流

11、avcodec_close();//关闭解码器

12、avformat_close_input_file();//关闭输入文件

 

二、详解:

1、AVCodecContext:描述编解码器上下文的数据结构,包含编解码器需要的参数信息(位于:avcodec.h)

typedef struct AVCodecContext {

     .....
} AVCodecContext;


说明:

单纯使用libavcodec,参数信息需要调用者进行初始化;使用整个FFMPEG库,在调用avformat_open_input和avformat_find_stream_info时根据文件头信息及媒体流内头部信息初始化。


2、AVStream:描述一个媒体流(存储视频/音频流信息的结构体,位于:avformat.h)
typedef struct AVStream {
    ......
} AVStream;

 

 

主要变量:

int index:标识视频/音频流

AVCodecContext *codec:视频/音频流的AVCodecContext

AVRational time_base:时间基准,真正的时间 =PTS*time_base

int64_t duration:该视频/音频流时间长度

AVDictionary *metadata:元数据信息

AVRational avg_frame_rate:帧率

AVPacket attached_pic:附加图片


3、AVFormatContext:描述媒体文件或媒体流构成和基本信息(包含码流参数较多,位于:avformat.h)
typedef struct AVFormatContext {
......
} AVFormatContext;

 

AVFormatContext是一个很重要的数据结构,很多函数会使用它作为参数;是FFMPEG解封装(flv,mp4,rmvb,avi)功能的结构体。

主要变量:

struct AVInputFormat *iformat:输入数据的封装格式

AVIOContext *pb:输入数据缓存

unsigned int nb_streams:音视频流个数

AVStream **streams:音视频流

char filename[1024]:文件名

int64_t duration:时长(单位:us)

int bit_rate:比特率

AVDictionary *metadata:元数据



4、AVPacket:存储压缩编码数据相关信息的结构体(位于:avformat.h)

typedef struct AVPacket {
   ......          
} AVPacket;

 

 

主要变量:

uint8_t *data:压缩编码数据,一个AVPacket的data通常对应一个NAL。

int   size:data的大小

int64_t pts:显示时间戳

int64_t dts:解码时间戳

int   stream_index:标识该AVPacket所属的视频/音频流。

 

三、API
1、int avformat_open_input(AVFormatContext **ic_ptr,const char *filename,AVInputFormat *fmt,AVDictionary **options);
作用:打开文件或URL,并使基于字节流的底层输入模块得到初始化;解析多媒体文件或多媒体流的头信息,创建AVFormatContext结构并填充其中的关键字段,依次为各个原始流建立AVStream结构。

参数:
ic_ptr:用于返回avformat_open_input内部构造的一个AVFormatContext结构体。
filename:指定文件名。
fmt:用于显式指定输入文件的格式,如果设为空则自动判断其输入格式。
options:传入的附加参数。

 

说明:这个函数通过解析多媒体文件或流的头信息及其他辅助数据,能够获取足够多的关于文件、流和编解码器的信息,但任何一种多媒体格式提供的信息都是有限的,而且不同的多媒体软件制作对头信息的设置各有不同,另外这些软件在产生多媒体内容时难免引入错误,这种情况下并不能保证获取到所有需要的信息,这是就要考虑另一个函数:avformat_find_stream_info。

 

2、int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);

作用:用于获取必要的编解码器参数。需要得到各媒体流对应编解码器的类型和id,这是两个定义在avutils.h和avcodec.h中的枚举:
enum AVMediaType {
     AVMEDIA_TYPE_UNKNOWN = -1,
     AVMEDIA_TYPE_VIDEO,
     AVMEDIA_TYPE_AUDIO,
     AVMEDIA_TYPE_DATA,
     AVMEDIA_TYPE_SUBTITLE,
     AVMEDIA_TYPE_ATTACHMENT,
     AVMEDIA_TYPE_NB
};


enum CodecID {
     CODEC_ID_NONE,
     CODEC_ID_MPEG1VIDEO,
     CODEC_ID_MPEG2VIDEO,
     CODEC_ID_MPEG2VIDEO_XVMC,
     CODEC_ID_H261,
     CODEC_ID_H263,

CODEC_ID_H264,
     ...

};

 

若媒体格式的数据流具有完整头信息,可以通过avformat_open_input得到编解码器的类型和id;否则,需要通过avformat_find_stream_info函数获取。此外,对于音频编解码器,时间基准、采样率、声道数、位宽、帧长度与视频编解码器图像大小、色彩空间等也需要从avformat_find_stream_info函数得到。

3、int av_read_frame(AVFormatContext *s, AVPacket *pkt);

作用:用于从多媒体文件或多媒体流中读取媒体数据,数据由AVPacket结构pkt来存放。对于音频数据,若是固定比特率,则pkt中装载一个或多个音频帧;若为可变比特率,则pkt中装载一个音频帧。对于视频数据,pkt中装载有一个视频帧。注:当再次调用本函数之前,需使用av_free_packet释放pkt所占用的资源。


4、int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);

作用:通过改变媒体文件的读写指针来实现对媒体文件的随机访问,大多源于媒体播放器的快进、快退等功能。
 

参数:
s:AVFormatContext指针,avformat_open_input返回得到。
stream_index:指定媒体流。
timestamp:时间标签。。
flags:定位方式。


5、void av_close_input_file(AVFormatContext *s);
作用:关闭媒体文件,释放资源,关闭物理IO。


6、AVCodec *avcodec_find_decoder(enum CodecID id);
   AVCodec *avcodec_find_decoder_by_name(const char *name);
作用:根据指定解码器ID或者解码器名称查找相应的解码器并返回AVCodec *。

 

7、int avcodec_open(AVCodecContext *avctx, AVCodec *codec);
作用:根据输入的AVCodec指针具体化AVCodecContext结构。在调用该函数之前,首先调用avcodec_alloc_context分配一个AVCodecContext结构,或调用avformat_open_input获取媒体文件中对应媒体流的AVCodecContext结构;此外,通过avcodec_find_decoder获取AVCodec结构。

 

8、int avcodec_decode_video2(AVCodecContext *avctx,AVFrame *picture,int *got_picture_ptr,AVPacket *avpkt);

作用:解码视频帧。

参数:

avctx:解码器上下文。

picture:输出数据。

got_picture_ptr:指示是否有解码数据输出。

avpkt:输入数据。


9、int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *avpkt);

作用:解码音频帧。输入数据在AVPacket结构中,输出数据在frame中,got_frame_ptr表示是否有数据输出。

 

参数:

avctx:解码器上下文。

frame:输出数据。

got_frame_ptr:指示是否有解码数据输出。

avpkt:输入数据。


10、int avcodec_close(AVCodecContext *avctx);
作用:关闭解码器,释放avcodec_open中分配的资源。
        

三、大体代码流程

 

[cpp] view plain copy

  1. int main(int argc, char **argv)  
  2. {  
  3.     AVFormatContext* pCtx = NULL;  
  4.     AVCodecContext *pCodecCtx = NULL;  
  5.     AVCodec *pCodec = NULL;  
  6.     AVPacket packet;  
  7.     AVFrame *pFrame = NULL;  
  8.     FILE *fpo1 = NULL;  
  9.     FILE *fpo2 = NULL;  
  10.     int nframe;  
  11.     int err;  
  12.     int got_picture;  
  13.     int picwidth, picheight, linesize;  
  14.     unsigned char *pBuf;  
  15.     int i;  
  16.     int64_t timestamp;  
  17.     struct options opt;  
  18.     int usefo = 0;  
  19.     struct audio_dsp dsp;  
  20.     int dusecs;  
  21.     float usecs1 = 0;  
  22.     float usecs2 = 0;  
  23.     struct timeval elapsed1, elapsed2;  
  24.     int decoded = 0;  
  25.   
  26.     av_register_all();  
  27.     av_log_set_callback(log_callback);  
  28.     av_log_set_level(50);  
  29.   
  30.     err = avformat_open_input(&pCtx, opt.finput, 0, 0);  
  31.     if (err < 0){  
  32.         printf("\n->(avformat_open_input)\tERROR:\t%d\n", err);  
  33.         goto fail;  
  34.     }  
  35.   
  36.     err = avformat_find_stream_info(pCtx, 0);  
  37.     if (err < 0){  
  38.         printf("\n->(avformat_find_stream_info)\tERROR:\t%d\n", err);  
  39.         goto fail;  
  40.     }  
  41.   
  42.     if (opt.streamId < 0){  
  43.         av_dump_format(pCtx, 0, pCtx->filename, 0);  
  44.         goto fail;  
  45.     }else{  
  46.         for (i = 0; i < pCtx->streams[opt.streamId]->codec->extradata_size; i++){  
  47.             if (i%16 == 0) printf("\n");  
  48.             printf("%2x ", pCtx->streams[opt.streamId]->codec->extradata[i]);  
  49.         }  
  50.     }  
  51.   
  52.     / *Try to open output file*/  
  53.     if (strlen(opt.foutput1) && strlen(opt.foutput2))  
  54.     {  
  55.         fpo1 = fopen(opt.foutput1, "wb");  
  56.         fpo2 = fopen(opt.foutput2, "wb");  
  57.         if (!fpo1 || !fpo2){  
  58.             printf("\n->error Open output file.\n");  
  59.             goto fail;  
  60.         }  
  61.         usefo = 1;  
  62.     }else{  
  63.         usefo = 0;  
  64.     }  
  65.   
  66.     if (opt.streamId >= pCtx->nb_streams){  
  67.         printf("\n->StreamId\tERROR\n");  
  68.         goto fail;  
  69.     }  
  70.   
  71.     if (opt.lstart > 0){  
  72.         err = av_seek_frame(pCtx, opt.streamId, opt.lstart, AVSEEK_FLAG_ANY);  
  73.         if (err < 0)  
  74.         {  
  75.             printf("\n->(av_seek_frame)\tERROR:\t%d\n", err);  
  76.             goto fail;  
  77.         }  
  78.     }  
  79.   
  80.    / *Config decoder*/  
  81.     if (!opt.nodec){  
  82.         /* prepare codec */  
  83.         pCodecCtx = pCtx->streams[opt.streamId]->codec;  
  84.    
  85.         if (opt.thread_count <= 16 && opt.thread_count > 0 ){  
  86.             pCodecCtx->thread_count = opt.thread_count;  
  87.             pCodecCtx->thread_type = FF_THREAD_FRAME;  
  88.         }  
  89.         pCodec = avcodec_find_decoder(pCodecCtx->codec_id);  
  90.         if (!pCodec){  
  91.             printf("\n->Can't find decoder!\n");  
  92.             goto fail;  
  93.         }  
  94.         err = avcodec_open2(pCodecCtx, pCodec, 0);  
  95.         if (err < 0){  
  96.             printf("\n->(avcodec_open)\tERROR:\t%d\n", err);  
  97.             goto fail;  
  98.         }  
  99.         pFrame = avcodec_alloc_frame();  
  100.    
  101.         / *Ready audio device* /  
  102.         if (opt.bplay){  
  103.            / *Audio device* /  
  104.             dsp.audio_fd = open(OSS_DEVICE, O_WRONLY);  
  105.             if (dsp.audio_fd == -1){  
  106.                 printf("\n-> Can't find audio device\n");  
  107.                 goto fail;  
  108.             }  
  109.   
  110.             dsp.channels = pCodecCtx->channels;  
  111.             dsp.speed = pCodecCtx->sample_rate;  
  112.             dsp.format = map_formats(pCodecCtx->sample_fmt);  
  113.             if (set_audio(&dsp) < 0){  
  114.                 printf("\n-> Can't set audio device\n");  
  115.                 goto fail;  
  116.             }  
  117.         }  
  118.     }  
  119.   
  120.     nframe = 0;  
  121.     while(nframe < opt.frames || opt.frames == -1)  
  122.     {  
  123.         gettimeofday(&elapsed1, NULL);  
  124.         err = av_read_frame(pCtx, &packet);  
  125.         if (err < 0){  
  126.             printf("\n->(av_read_frame)\tERROR:\t%d\n", err);  
  127.             break;  
  128.         }  
  129.     }  
  130.   
  131.     if (!opt.nodec && pCodecCtx)  
  132.     {  
  133.         avcodec_close(pCodecCtx);  
  134.     }  
  135.    
  136. fail:  
  137.     if (pCtx){  
  138.         avformat_close_input(&pCtx);  
  139.     }  
  140.     if (fpo1){  
  141.         fclose(fpo1);  
  142.     }  
  143.     if (fpo2){  
  144.         fclose(fpo2);  
  145.     }  
  146.     if (!pFrame){  
  147.         av_free(pFrame);  
  148.     }  
  149.     if (!usefo && (dsp.audio_fd != -1)){  
  150.         close(dsp.audio_fd);  
  151.     }  
  152.     return 0;  
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值