ffmpeg编解码流程.docx_第1页
ffmpeg编解码流程.docx_第2页
ffmpeg编解码流程.docx_第3页
ffmpeg编解码流程.docx_第4页
ffmpeg编解码流程.docx_第5页
免费预览已结束,剩余4页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

FFMPEG编解码流程一基础知识介绍在介绍FFMpeg编解码流程之前,先了解一下FFMpeg用到的头文件和库,还有一些主要的数据结构。1.头文件头文件的引入extern C#include libavcodec/avcodec.h#include libavformat/avformat.h#include libavutil/avutil.h#include libavutil/mem.h#include libavutil/fifo.h#include libswscale/swscale.h;libavcodec用于存放各个encode/decode模块,CODEC其实是Coder和Decoder的缩写,也就是编码解码器,用于各种类型声音和图像的编解码。libavformat用于存放muxer/demuxer模块,对音频视频格式的解析;用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能。libswscale:用于视频场景比例缩放、色彩映射转换;2.数据结构以下介绍的数据结构定义在libavcodec/avcodec.h中。AVFormatContextTypedef struct AVFormatContext AVOutputFormat *oformat; AVInputFormat *iformat; Unsigned int nb_streams; AVStream *streams; AVFormatContext是FFMpeg格式转换过程中实现输入和输出功能,保存相关数据的主要结构,其作用贯穿整个编解码过程。对于输入 输出需要分别对iformat和oformat赋值,在一个AVFormatContext结构变量中,oformat和iformat不能同时有值。streams中保存了媒体文件的流信息,在解码时由av_find_stream_info()函数初始化,编码时需要使用者建立流并手动初始化,nb_streams是流的数量。AVStreamTypedef struct AVStream int index; AVCodecContext *codec; AVRational time_base; int64 duration; int64 nb_frames; AVStream保存与数据流相关的编解码器,数据段等信息。codec保存的是encoder或者decoder的上下文信息。time_base在解码时由解码器设置,编码时在av_write_header()函数中设置,在计算pts时会用到。Duration是流的总时间长度,nb_frames记录流的总帧数。 AVCodecContext Typedef struct AVCodecContext Struct AVCodec *codec; enum AVMediaType codec_type; enum CodecID codec_id; 编解码器共用AVCodecContext和AVCodec结构,codec中保存编解码器参数,codec_type保存的AVMEDIA_TYPE_VIDEO,AVMEDIA_TYPE_AUDIO等媒体流的类型,codec_id保存编解码方式。AVCodecContext中还包含其他一些重要的数据,如video的width,height,pix_fmt,audio的sample_rate等参数。这些参数在解码时由decoder设置,而编码是要有用户手动设置,如果参数设置错误或者没有设置,会导致avcodec_open()调用失败。AVCodec Typedef struct AVCodec.Enum AVMediaType type;Enum CodecID id; int (*init)(AVCodecContext *); int (*encode)(AVCodecContext *, uint8_t *buf, int buf_size, void *data);int (*close)(AVCodecContext *); int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt); AVPacket Typedef struct AVPacket Int64 pts; Int64 dts; Uint8_t *data; Int size; Int stream_index; Int flags; . AVPacket在读媒体文件和输出媒体文件时都会用到。在读媒体文件时av_read_frame(&Packet)会初始化AVPacket数据结构,而用于写媒体文件时,用户需要自己设置参数,以上列出的变量是需要用户自己设置的。pts是显示时间戳,在编码是需要结合流的time_base和编码器的time_base计算,以保持音视频同步播放。dts是解码时间戳。data中保存了读媒体文件或者需要输出的数据。stream_index在流的序号。AVPacket结构变量在使用前要调用av_init_packet(AVPacket *pkt)初始化,使用完要调用av_free_packet(AVPacket *pkt)释放资源。二FFMPEG编解码流程1初始化系统环境avcodec_init();/初始化libavcodecav_register_all(); /初始化 libavformat和注册所有的muxers、/demuxers和protocolsav_log_set_callback(stateFunc);/注册回调函数 av_register_all()主要包括avcodec_register_all()函数和一大堆注册demuxer、muxers、protocols的宏。avcodec_register_all()包括一大堆注册encodec、decoder、parser、bitstream filter的宏。av_register_all()函数只需要调用一次,它注册了所有支持的媒体文件格式和编解码器的库,当媒体文件打开时会自动匹配合适的编解码器。注册回调函数的原型为 void av_log_set_callback(void(*callback)(void*,intconstchar*,va_list),FFMpeg 目录下libavutil/log.c中有一个默认的回调函数,av_log_default_callback(void *ptr,int level,const char *fmt,va_list),可以模仿这个函数写自己的回调函数。注册回调函数之后,我们就可以获得FFMpeg底层运行时错误信息。/查看设置的信息void av_dump_format(AVFormatContext *ic,int index,const char *url,int is_output);该函数将相应流及编解码器的信息显示到标准错误输出中,ic是对应输入 输出文件的上下文信息结构变量,url为对应输入或输出文件名,is_output 输入文件时取值0,输出文件时取值1,index可以取值0。2读取输入文件头信息 AVFormatcontext *pIC;av_open_input_file(&pIC, filename,NULL,0,NULL); /打开视频文件,并将文件头信息保存在AVFormatContext *pIC数据结构/中返回,filename为输入文件名。av_find_stream_info(pIC);/初始化文件音视频流的信息pIC-streamsav_open_input_file()函数打开一个媒体文件,如果媒体文件存在头信息,就读取文件头信息来初始化pIC,主要初始化pIC-iformat结构,函数的最后三个参数用来指定特殊的文件格式,缓冲大小和格式参数,但如果把它们设置为空NULL或者0,libavformat将自动检测这些参数。这个函数只是检测了文件头信息,所以我们需要检测文件中流的信息。av_find_stream_info()函数,从文件中提取流的信息,然后填充在AVFormatContext结构的streams区域,最主要的初始化了流对应的解码器上下文信息和流所属的类型。3初始化音视频解码器/穷举所有的流,查找音视频流,视频流举例int videostream = -1;for(int i = 0; i nb_stream; +i) if(pIC-streamsindex-codec-codec_type = AVMEDIA_TYPE_VIDEO) videostream = i; break; AVCodecContext *pICCtx = pIC-streamsvideostream-codec; AVCodec *pIC =avcodec_find_decoder(pICCtx-codec_id);/查找相应的解码器 avcodec_open(pICCtx,pIC);/ 打开对应的解码器/应记录输入文件的流信息,以便建立输出文件流时使用。FFMpeg中定义媒体文件中流的类型包括AVMEDIA_TYPE_VIDEO,AVMEDIA_TYPE_AUDIO等,这儿我们只关心video和audio类型的流,找到音视频流并打开相应的解码器。4初始化音视频编码器 .根据输出文件猜测音视频编码器类型 AVOutputFormat * pO = av_guess_format(NULL,filename,NULL); /根据输出文件名 或者后缀猜测音视频编码器格式 AVFormatContext *pOut = avformat_alloc_context(); /最后使用avformat_free_context()释放 pOut-oformat = pO;av_guess_format()主要根据输出文件格式猜测支持的音视频编码器,初始化pO-audio_codec和pO-video_codec,后面用户可以根据猜测出的音视频编码器类型创建编码器。.为输出文件添加音视频流AVStream *pS = av_new_stream(pOut,NULL);输出文件中流的建立需要对应输入文件中存在的流,而流的序号只跟创建的顺序有关,应记录输入 输出文件流的序号对应关系,作为最后写入流数据的参考。3.初始化编码器,视频编码器举例AVCodecContext *pOCCtx = pS-codec;AVCodec *pOC = avcodec_find_encoder(pOut-video_codec); avcodec_open(pOCCtx,pOC);/根据猜测出的编码器类型查询并打开编码器对于编码器初始化,需要手动设置一些必须的AVCodecContext结构的参数。视频必须设的参数: pOCCtx-bit_rate pOCCtx-width 和pCCtx-height-height pOCCtx-time_base pOCCtx-pix_fmt pOCCtx-gop_sizepOCCtx-max_b_frame音频参数: pOCCtx-sample_rate pOCCtx-sample_fmt pOCCtx-bit_rate pOCCtx-channels这些参数的设定需要参照对应编码器类型,如果设置错误或者没有设置都会导致avcodec_open()函数调用失败。如果注册了回调函数,可以看到是那些参数设置错误。用户也可以调用avcodec_get_context_defaults3(AVCodecContext *s,AVCodec *codec),根据编码器类型,初始化编码器上下文结构的默认值。5. 创建编码缓冲区.分配视频编码缓冲区AVFrame结构用来保存视频解码之后的一帧数据,avcodec_alloc_frame()函数分配AVFrame资源,在程序结尾需要调用av_free()释放分配的资源。如果编解码器指定的图片格式不相同,如mov格式的媒体文件视频解码器pix_fmt = PIX_FMT_YUV422,而我们要编码为MP4格式时设置的视频编码器pix_fmt=PIX_FMT_YUV420P,那么我们需要在编码之前进行格式的转换,我们需要定义一个SwsContext数据结构和分配一个保存转码后数据缓冲区,SwsContext结构在libswscaleswscale.h头文件中定义,主要用于视频分别率和色彩空间的变换。AVFrame *pFrame = avcodec_alloc_frame();AVFrame *pFrameTemp = avcodec_alloc_frame();/计算width*height大小的PIX_FMT_YUV420P格式图片所需的空间int pictureNum = avpicture_get_size(PIX_FMT_YUV420P,widt,height);uint8_t *buffer = (uint8_t)av_malloc(pictureNum*sizeof(uint8_t);/将分配的空间与pFrameTemp关联起来avpicture_fill(AVPicture*)pFrameTemp,buffer,PIX_FMT_420P,width,height); .分配音频缓冲区 int audio_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE*100; uint8_t *audio_buffer = (uint8_t*)av_malloc(audio_buffer_size*sizeof(uint8_t); /保存解码后音频数据 int sample_buffer_size = 10000; uint8_t *sample_buffer = (uint8_t*)av_malloc(sample_buffer_size*sizeof(uint8_t); /保存编码后音频数据 编码音频的时候,我是将解码出的音频数据直接编码输出的,并没有涉及重采样的问题,所以只分配了保存解码后数据和编码后数据的缓冲区。 如果需要重采样,则需要涉及struct ReSampleContext,struct AVFiFoBuffer。6打开输出媒体文件,写入头信息 /设置初始化参数av_set_parameters(AVFormatContext *s,NULL);即使没有参数,也建议调用该函数。/打开输出媒体文件int avio_open(AVIOContext *s,const char *url,int flags); 该函数打开一个本地媒体文件,并初始化一个AVIOContext结构变量,该函数也可以用于打开一个网络流媒体文件,但对于本地文件相当于open read等的调用,url为文件路径名,flags是打开方式(读或者写)。调用时将AVFormatContext结构中成员变量AVIOContext *pb赋值给s。/流头信息写入媒体文件中 av_write_header(AVFormatContext *s); 该函数还会初始化流数据结构AVStream中的time_base成员变量。 7.解码 解码的过程是从输入文件的流中不停的读入数据,根据流中对应解码器解码,但对于音视的处理方式并不同。. av_read_frame(AVFormatContext *pIn,AVPacket *Packet) 不停的从输入媒体文件的流中读出一个包的数据,数据保存在Packet中,这 一个包的数据未必包含一个完整的视频帧的数据。 .视频帧解码,编码,写入对应视频流中 int avcodec_decode_video2(AVCodecContext *avctx,AVFrame *picture,int &finished,const AVPacket *avpkt); finished 0 即从包中解出了一完整的帧,可以进行下一步操作,若finished 0,即包中数据不足以解码出一帧图片,则包中数据会被先保存起来,读下一包数据,结合下一包的数据解码出完整的一帧图片为止。每次读数据前记的调用av_free_packet()函数。 .音频帧解码int avcodec_decode_audio3(AVCodecContext *avctx,int16_t *samlples,int *frame_size_

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论