关键词不能为空

当前您在: 主页 > 英语 >

ffmpeg主要数据结构和函数

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-02-06 02:13
tags:

-

2021年2月6日发(作者:shoppingmall)


FFMpeg


中比较重要的函数以及数据结构如下:




1.


数据结构:




(1) AVFormatContext



(2) AVOutputFormat



(3) AVInputFormat



(4) AVCodecContext



(5) AVCodec



(6) AVFrame



(7) AVPacket



(8) AVPicture



(9) AVStream



2.


初始化函数:




(1) av_register_all()



(2) avcodec_open()



(3) avcodec_close()



(4) av_open_input_file()



(5) av_find_input_format()



(6) av_find_stream_info()



(7) av_close_input_file()



3.


音视频编解码函数:




(1) avcodec_find_decoder()



(2) avcodec_alloc_frame()



(3) avpicture_get_size()



(4) avpicture_fill()



(5) img_convert()



(6) avcodec_alloc_context()



(7) avcodec_decode_video()



(8) av_free_packet()



(9) av_free()



4.


文件操作:




(1) avnew_steam()



(2) av_read_frame()



(3) av_write_frame()



(4) dump_format()



5.


其他函数:




(1) avpicture_deinterlace()



(2) ImgReSampleContext()



以下就根据,以上数据结构及函数在


ffmpeg

< br>测试代码


output_example.c


中出现的前 后顺进行分析。



交待完毕进入正题。




一.


FFMpeg


中的数据结构:




I. AVFormatContext



一般在使用


ffmpeg sdk


的代 码中


AVFormatContext


是一个贯穿始终的数据结 构



很多函数都要用到


它作为参数。< /p>


FFmpeg


代码中对这个数据结构的注释是:

< br>format I/O context


此结构包含了一个视频流的格


式内容。其中存有了


AVInputFormat



or AVOutputFormat


同一时间

< p>
AVFormatContext


内只能存在其中一


个)




AVStream



AVPacket


这几个重要的数据结构以及 一些其他的相关信息



比如


title ,author,copyright


等。还有一些可能在编解码中会用到的信息,诸如 :


duration, file_size, bit_rate

等。参考


avformat.h


头文


件。




Useage:



声明:




AVFormatContext *oc; (1)



初始化:



由于


AVFormatConext


结构包含许多信息因此初始化过程是分步完成,而且有 些变量如果


没有值可用,也可不初始化。但是由于一般声明都是用指针因此一个分配内存 过程不可少:




oc = av_alloc_format_context(); (2)


< br>结构中的


AVInputFormat*


(或

< p>
AVOutputFormat*


)是一定要初始化的,基本上这是编译码 要使用什



codec


的依据所在:< /p>




oc->oformat = fmt; or oc->iformat = fmt; (3)



其中


AVOutputFormat* fmt



AVInputFormat* fmt




AVInputFormat and AVO utputForm


at


的初始


化在后 面介绍。随后在参考代码


output_example.c


中 有一行:




snprintf(oc-filename, sizeof(oc-


>filename), “%s”, filename); (4)



还不是十分清楚有什么作用,估计是先要在输出文件 中写一些头信息。





在完成以上步骤後,


(初始化完毕


AVInpu tFormat*


(或


AVOutputFormat*



以及


AVFormatContext



接下来就是要利用


oc

< br>初始化本节开始讲到的


AVFormatContext


中的第二个重要结构。


AVStream


(假设已


经有了声明


AVStream *video_st


。参考代码用了一个函数来完成初始化,当然也可以在主函数中做,传递


进函数的参数是


oc



fmt->video_co dec


(这个在下一节介绍


(29)


) :




vdeo_st = add_video_stream(oc, fmt->video_codec); (5)



此函数会在后面讲到


AVStrea m


结构时分析。



< br>AVFormatContext


最后的一个设置工作是:




if( av_set_paramters(oc,NULL) < 0){ (6)



//handle error;



}



dump_format(oc, 0, filename, 1); (7)



作用就是看看先前的初始化过程中设置的参数是否符合规范, 否则将报错。




上面讲的都是初始化 的过程



包括


AVFormatCon text


本身的和利用


AVFormatContext


初始化其他数


据结构的。接下来要讲讲整个的编解码过程。我想先将< /p>


ouput_example.c



ma in


函数内的编解码函数框


架描述一下。这样比较清晰,而且编 码者为了结构清晰,在写


ouput_example.c


的过 程中也基本上在


main


函数中只保持


AVFormatContext



AVStream


两个数据结构





AVOutputFormat


其实也在但是包含在

< p>
AVFormatContext


中了)。




// open video codec and allocate the necessary encode buffers



if(video_st)



open_video(oc, video_st); (8)



// write the stream header, if any



av_write_header(oc); (9)



// encode and decode process



for(; ){



write_video_frame(oc, video_st); (10)



// break condition…here



}



//close codec



if(video_st)



close_video(oc, video_st); (11)



//write the trailer , if any



av_write_trailer(oc); (12)



// free the streams



for(i=0; ib_streams; i++){



av_freep(&oc->streams[i]->codec); (13)



av_freep(&oc->streams[i]); (14)



}



//close the ouput file



if(!(fmt->flags & AVFMT_NOFILE)){



url_fclose(&oc->pb); (15)



}



av_free(oc); (16)


通过以上的一串代码,就可以清晰地看出


AVFormatContex*


oc



AVStream*


video_st


是在使用


ffmpeg SD K


开发时贯穿始终的两个数据结构。以下,简要介绍一下三个标为红色的函数,他们是参 考代码


output_example.c


开发者自行定义的函 数。这样可以使整个代码结构清晰,当然你在使用


ffmpeg SDK



也可以在主函数中完成对应的功能。在后面我们会专门针对这三个函



数做分析。




1. open_video(oc, video_st);



此函数主要是对视频编码器(或解码器)的初始化过程。初始 化的数据结构为


AVCodec*


codec



AVCodecContext* c


包括用到了的


SDK


函数有:




c = st->codec;



codec = avcodec_find_encoder(c->codec_id); //


编码时,找编码器



(17)



codec = avcodec_find_decoder(c->codec_id); //


解码时,找解码器



(18)




AVCodecContex< /p>


是结构


AVStream


中的一个数据结 构



因此在


AVStream


初始化後


(5)


直接复值给

c





// internal open video codec



avcodec_open(c,codec); (19)



// allocate video stream buffer



// AVFrame *picture



// uint8_t *video_outbuf



video_outbuf_size=200000;



video_outbuf = av_maloc(video_outbuf_size); (20)



// allocate video frame buffer



picture = alloc_picture(c->pix_fmt, c->width, c->height); (21)



上述三步比较容易理解,打开视频编解码


codec


、分配输出流缓存大小、分配每一帧图像缓存大小。


其中


AVFrame


也是


ffmpeg


中主要数据结构之一。这一步


(8)

< p>
是对编解码器的初始化过程。




2. write_video_frame(AVFormatContext *oc, AVStream *st)



这个函数中做了真 正的编解码工作,其中的函数比较复杂先列出来慢慢分析。




用到的数据结构有


AVCodecContext *c, SwsContext *img_convert_ctx


。其中

SwsContext


是用来变


换图像格式的。比如


yuv422


变到


yuv420


等,当然也用到函数,见下面列表。




fill_yuv_image(tmp_picture, frame_count, c->width, c->height); (22)



sws_scale(img_convert_ctx, tmp_picture->, tmp_picture->linesize,



0, c->height, picture->data, picture->linesize); (23)



img_convert_ctx = sws_getContxt(c->width, c->height, PIX_FMT_YUV420P, (24)



c->width, c->heigth, c->pix_fmt, sws_flags, NULL, NULL, NULL);




由于参考代码中做的是一个编码。因此,它总是要求编码器 输入的是


yuv


文件,而且是


yuv4 20


格式


的。就会有了以上一些处理过程。接下来调用编码器编 码,数据规则化(打包)用到


AVPacket


,这也是


ffmpeg


中一个比较不好理解的地方。




out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture); (25)



AVPacket pkt;



av_init_packet(&pkt); (26)



//……handle pkt process, we will analyze later



ret = av_write_frame(oc, &pkt); (27)




encode


就一定会有


d ecode



而且


ffmpeg


专为解码而生



但是为什么在参考代码中只用 了


encoder


呢?个人猜想是因为


encode


只是用


yuv420


来编 码,这样的


yuv420


生成比较容易,要是用到解码的化,< /p>


还要在代码中附带一个其他格式的音视频文件


< br>在源代码


libavcodec


文件夹中有一个


apiexample.c


的参考


代码,其中就 做了编解码。有空的化我会分析一下。




3. close_video(AVFormatContext *oc, AVStream *st)



avcodec_close(st->codec);



av_free(picture->data[0]);



av_free(picture);



av_free(video_outbuf);




比较容易理解,不多说了。




以上一大段虽然名为介绍


AVFor matContext


。但基本上把


ouput_exampl e.c


的视频编码部分的框架


走了一遍,其一是想说明结构


AVFormatContext


的重要性,另一方面也是希望对使 用


FFMpeg


SDK


开发


者有一个大致的框架。



其实,真正的一些编码函数,内存分配函数在


SDK


中都已 经封装好了,只要搞清楚结构就能用了。


而开发者要做的就是一些初始化的过程,基本上 就是针对数据结构


1


的初始化。





II. AVOutputFormat



虽然简单(初始化)但是十 分重要,他是编解码器将要使用哪个


codec




指示



。在其成员数据中 最


重要的就是关于视频




codec


的了:


enum CodecID video_codec;



AVOutputFormat *fmt;



fmt = guess_format(NULL, filename, NULL); (28)



根据


fi lename


来判断文件格式



同时也 初始化了用什么编码器



当然,


如果是 用


AVInputFormat *fmt


的化,就是


fix


用什么解码器。(指定输出序列


->fi x


编码器,指定输入序列


->fix


解 码器?)




III. AVStream



AVStream


作为继


AVFormatContext


後第二个贯穿始终的 结构是有其理由的。他的成员数据中有


AVCodecContext

< br>这基本的上是对所使用的


Video Codec


的参数 进行设定的


(包括


bit rate


、 分辨率等重要


信息)。同时作为


“Stream”


,它包含了







这个概念中的一些数据,比如:帧率(< /p>


r_frame_rate


)、基本时间计量单位(


time_base


)、(需要


编解码的)首帧位置 (


start_time


)、持续时间(


duration


)、帧数(


nb_frames

< p>
)以及一些


ip


信息。当然


后面的这些信息中有些不是必须要初



< br>始化的,但是


AVCodecContex


是一定要初始 化的,而且就是作为初始化


AVStream


最重要的一个部< /p>


分。我们在前面就谈到了


AVStream


的初始化函数


(5)


,现在来看看他是怎么做的:

< p>



// declaration



AVStream *video_st;



video_st = add_video_stream(oc, fmt->video_codec);



static AVStream *add_video_stream(AVFormatContex *oc, int codec_id){ (29)



AVCodecContext *c; // member of AVStream, which will be initialized here



AVStream *st; // temporary data, will be returned



st = av_new_stream(oc, 0); (30)



c = st->codec;



//


以下基本是针对


c


的初始化过程。包括比特率、分辨率、


GOP


大小等 。




……



//


以下的两行需要注意一下,特别是使用

< br>MP4




< br>if(!strcmp(oc->oformat-


>name,


|| !strcmp(oc->oformat-


>name, “3gp”))



c->flags |= CODEC_FLAG_GLOBAL_HEADER;



//



st


传给


video_st;



return st;



}



以上代码中,有几点需要注意的。一个是

(30)



c = st->codec

< br>是一定要做的,当然这是编程中最基


本的问题,


(30)


是将


st


这个


AVSteam


绑定到


AVFormatContext* oc


上。后面的


c = st->codec

< br>是将


c


绑定


< br>st



AVCodecContext

< br>上。其二是对


c


的初始化过程中,


ouput_example.c


里做的是一些基本的配置,


当然作为使用者的你还希望对


codec


加入其他的一些编解码 的条件。




可以参考


avcodec.h


里关于


AVCodecConte xt


结构的介绍,注释比较详细的。



关于


AVStream



使用在前面介 绍


AVFormatContext


时已有所涉及,在主函数中 三个编解码函数中


(8)



(10)< /p>



(11)


中。观察

相关的代码,可以发现主要还是将


AVStream


中的< /p>


AVCodecContext


提取出来,再从中提取出


AVCodec


结构如在


(8)


中:




// open_video(oc, video_st);



// AVFormatContext *oc, AVStream *st



AVCodec *codec;



AVCodecContext *c;



c = st->codec;



codec = avcodec_find_encoder(c->codec_id); (31)



// open the codec



avcodec_open(c, codec); (32)




同样,我们可以看 到在


(10)(write_video_frame())



AVFrame


也是做为传递


AVCo decContext


结构


的载体而存在。(

< br>11




< br>(close_video())


比较简单,不熬述。




IV. AVCodecContext



“mp4”)


||


!strcmp(oc


->oformat-


>na me,


“mov”)


此结构在


Ffmpeg SDK


中的注释是



main external api structure


其重要性可见一斑


而且在


avcodec


它的定义 处,对其每个成员变量,都给出了十分详细的介绍。应该说


AVCodecContex t


的初始化是


Codec


使

< p>


中最


重要


的一


环。


虽然



前面



AVStream



已经


有所



及,

但是


这里


还是


要在


说一




AVCodecCo ntext


作为


Avstream


的一 个成员结构,必须要在


Avstream


初始化後


(30)


再对其初始化


(AVStream








AVFormatContex)





< br>员

















outpu t_example.c


中用到了,其他的请查阅


avcode c.h


文件中介绍。




// static AVStream *add_video_stream(AVFormatContext *oc, int codec_id)



AVCodecContext *c;



st = av_new_stream(oc, 0);



c = st->codec;



c->codec_id = codec_id;



c->codec_type = CODEC_TYPE_VIDEO;



c->bit_rate = 400000; // 400 kbits/s



c->width = 352;



c->height = 288; // CIF



//


帧率做分母,秒做分子,那么


t ime_base


也就是一帧所用时间。(时间基!)




c->time_ = STREAM_FRAME_RATE;



c->time_ = 1;



c->gop_size =12;



// here define:



// #define STREAM_PIX_FMT PIX_FMT_YUV420P



// pixel format, see PIX_FMT_xxx



// -encoding: set by user.



// -decoding: set by lavc.



c->pix_fmt = STREAM_PIX_FMT;



除了以上列出了的。还有诸如指定运动估计算法的


:


me_method


。量化参数、最大


b


帧数:


max_b_frames


。码率控制 的参数、差错掩盖


error_concealment


、模式 判断模式:


mb_decision (


这个参数


蛮有意思的,可以看看


avcodec.h 1566



)



Lagrange multipler


参数:


lmin & lmax




宏块级


Lagrange


multi pler


参数:


mb_lmin & mb_lmax



constant quantization parameter rate control method: cqp


等。




得一提的是在


AVCodecContext


中有两个成员数 据结构:


AVCodec



AVFra me



AVCodec


记录了所要使< /p>


用的


Codec


信息并且含有

< p>


5


个函数


< p>
init



encoder



close



decode



flush


来完成编解码工作


(参见


avcode.h 2072


行)

< p>


AVFrame


中主要是包含了编码後的帧信息 ,包括本帧是否是


key frame



*data[4]


定义的


Y



Cb



Cr


信息等, 随后


详细介绍。



< br>初始化後



可以说


AVCode cContext



(8)&(10)


中大显身手



先在


(8)open_v ideo()


中初始化


AVCodec


*codec


以及


AVFrame*



picture





// AVCodecContext *c;



codec = avcodec_find_encoder(c->codec_id);



……



picture = alloc_picture(PIX_FMT_YUV420P, c->width, c->height);



後在


wr iter_video_frame(AVFormatContext *oc, AVStream *st )


中作为一个编解码器的主要参数被利


用:



AVCodecContext *c;



c = st->codec;



……



out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);



V



AVCodec



结构


AVCodec


中成员变量和成员函数比较少,但是很重要。他包含了


CodecID


,也就是用哪个


Codec


< br>



像素格式信息。还有前面提到过的

< br>5


个函数(


init



encode



close


decoder



flush< /p>


)。顺便提


一下,虽然在参考代码


out put_example.c


中的编码函数用的是


avcode c_encode_video


(),我怀疑在其


中就是调用了


AVCodec



encode


函数,他们传递的参数和返回值都是一致的,当然还没有得到确认,有


兴趣可以看看


ffmpeg


源代码。在参考代码中,

< p>
AVCodec


的初始化後的使用都是依附于


AV CodecContex



前者是后者的成员。在


AVCodecContext


初始化後(


add_ video_stream()




A VCodec


也就能很好的初始


化了:




//


初始化




codec = avcodec_find_encoder(c->codec_id); (33)



//


打开


Codec



avcodec_open



c, codec




(34)



VI. AVFrame



AVFrame


是个很有意思的结构,它本身是这样定义的:




typedef struct AVFrame {



FF_COMMON_FRAME



}AVFrame;


< p>
其中,


FF_COMMON_FRAME


是以一个 宏出现的。由于在编解码过程中


AVFrame


中的数据是要经


常存取的。为了加速,要采取这样的代码手段。



-


-


-


-


-


-


-


-



本文更新与2021-02-06 02:13,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/604801.html

ffmpeg主要数据结构和函数的相关文章

  • 爱心与尊严的高中作文题库

    1.关于爱心和尊严的作文八百字 我们不必怀疑富翁的捐助,毕竟普施爱心,善莫大焉,它是一 种美;我们也不必指责苛求受捐者的冷漠的拒绝,因为人总是有尊 严的,这也是一种美。

    小学作文
  • 爱心与尊严高中作文题库

    1.关于爱心和尊严的作文八百字 我们不必怀疑富翁的捐助,毕竟普施爱心,善莫大焉,它是一 种美;我们也不必指责苛求受捐者的冷漠的拒绝,因为人总是有尊 严的,这也是一种美。

    小学作文
  • 爱心与尊重的作文题库

    1.作文关爱与尊重议论文 如果说没有爱就没有教育的话,那么离开了尊重同样也谈不上教育。 因为每一位孩子都渴望得到他人的尊重,尤其是教师的尊重。可是在现实生活中,不时会有

    小学作文
  • 爱心责任100字作文题库

    1.有关爱心,坚持,责任的作文题库各三个 一则150字左右 (要事例) “胜不骄,败不馁”这句话我常听外婆说起。 这句名言的意思是说胜利了抄不骄傲,失败了不气馁。我真正体会到它

    小学作文
  • 爱心责任心的作文题库

    1.有关爱心,坚持,责任的作文题库各三个 一则150字左右 (要事例) “胜不骄,败不馁”这句话我常听外婆说起。 这句名言的意思是说胜利了抄不骄傲,失败了不气馁。我真正体会到它

    小学作文
  • 爱心责任作文题库

    1.有关爱心,坚持,责任的作文题库各三个 一则150字左右 (要事例) “胜不骄,败不馁”这句话我常听外婆说起。 这句名言的意思是说胜利了抄不骄傲,失败了不气馁。我真正体会到它

    小学作文