1.AVFormatConext
AVFormatConext是一个贯穿全局地数据结构,AVFormatConext结构包含很多信息,很多函数都要用它作为参数。
初始化AVFormatConext示例代码:
AVFormatContext *pFormatCtx; pFormatCtx=avformat_alloc_context();
2.AVInputFormat
AVInputFormat是FFmpeg的解复用器对象,AVInputFormat是类似COM接口地数据结构,表示输入文件容器格式,着重于功能类型,一种文件容器格式对应一个AVInputFormat结构,在程序运行时有多个案例。
3.AVStream
AVStream是存储每一个视频/音频流信息的结构体。解复用器的目的就是从容器中分离(解析出来)不同的流,FFmpeg中的流对象为AVStream,它是由解复用器的read_header函数创建的,并保存在AVFormatConext的nb_streams(容器中的流条数)及stream数组中。
4.AVCodecContext
AVCodecContext是一个描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息。
初始化示例代码:
AVCodecContext *mAvContext = NULL; mAvContext = avcodec_alloc_context3(mVcodec);
5.AVPacket
FFmpeg 用AVPacket 来存放编码后的视频数据,AVPacket 保存了解复用之后、解码前的数据(仍然是压缩后的数据)和关于这些数据的一些附加信息,如显示时间戳(PTS)解码时间戳(DTS)数据时长、所在媒体流的索引等。
对于视频(Video)来说,AVPacket 通常包含一个压缩的,而音频 (Audio)则有可能包含多个压缩的帧。并且,一个 Packet 有可能是空的,不包含任何压缩数据,只含有 side dat(side data 指的是容器提供的关于 Packet 的一些附加信息。例如,在编码结束的时候更新一些流的参数)。
申请AVPacket:
AVPacket *packet = (AVPacket *) av_malloc(sizeof(AVPacket));
AVPacket源码解析:
typedef struct AVPacket { AVBufferRef *buf;//AVBufferRef类型的指针,用来管理data指针引用的数据缓存 int64_t pts;//显示时间戳 int64_t dts;//解码时间戳 uint8_t *data;//指向保存压缩数据的指针,这就是AVPacket实际的数据 int size; int stream_index;//流索引 int flags;//带有AV_PKT_FLAG属性的组合 AVPacketSideData *side_data;//填充容器的一些附加数据 int side_data_elems; int64_t duration;//Packet的时长 int64_t pos;//Packet的位置 #if FF_API_CONVERGENCE_DURATION attribute_deprecated int64_t convergence_duration; #endif } AVPacket;
6.AVCodec
AVCodec是存储编解码器信息的结构体,AVCodec Codec通过avcodec_find_decoder(codec_id)找到对应的Codec。
初始化AVCodec示例代码:
AVCodec *mVcodec = NULL; mVcodec = avcodec_find_decoder(codec_id);
7.AVFrame
AVFrame结构体一般用于存储原始数据(即非压缩数据,例如对视频来说是YUV、RGB,对音频来说是PCM),此外还包含了一些相关信息。
创建AVFrame
AVFrame *frame = av_frame_alloc();//分配一个AVFrame结构体,AVFrame结构体一般用于存储原始数据,指向解码后的原始帧
在解码过程中使用了两个AVFrame,这两个AVFrame分配缓存空间的方法不同:
- 一个AVFrame用来存放从AVPacket中解码出来的原始数据,这个AVFrame的数据缓存空间通过调用 avcodec_receive_frame(mAvContext, frame)来分配和填充。
result = avcodec_receive_frame(mAvContext, frame);
- 另一个AVFrame用来存放将解码出来的原始数据变换为需要的数据格式(例如RGB、RGBA)的数据,这个AVFrame需要手动分配数据缓存空间,代码如下:
AVFrame *rgb_frame = av_frame_alloc();//分配一个AVFrame结构体,指向存放转换成rgb后的帧 //缓存区 uint8_t *out_buffer= (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_RGBA, mAvContext->width,mAvContext->height)); //与缓存区相关联,设置rgb_frame缓存区 avpicture_fill((AVPicture *)rgb_frame,out_buffer,AV_PIX_FMT_RGBA,mAvContext->width,mAvContext->height);
释放AVFrame
av_frame_free(&frame); av_frame_free(&rgb_frame);
AVFrame源码解析:
typedef struct AVFrame { #define AV_NUM_DATA_POINTERS 8 uint8_t *data[AV_NUM_DATA_POINTERS]; int linesize[AV_NUM_DATA_POINTERS]; uint8_t **extended_data;//扩展的数据 int width, height;//视频的宽和高 int nb_samples;//每个信道的音频采样点个数 int format;//帧的像素格式 int key_frame;//1表示关键帧 0表示非关键帧 enum AVPictureType pict_type;//帧的图像类型 AVRational sample_aspect_ratio;//视频帧的采样率 int64_t pts;//显示时间戳 #if FF_API_PKT_PTS attribute_deprecated int64_t pkt_pts;//从AVPacket中复制的PTS #endif int64_t pkt_dts;//从AVPacket中复制的DTS int coded_picture_number;//按解码排序后的图像数 int display_picture_number;//按显示位置排序的图像数 int quality;//在1~FF_LAMBDA_MAX(256*128-1)之间取值 void *opaque;//私有数据 #if FF_API_ERROR_FRAME attribute_deprecated uint64_t error[AV_NUM_DATA_POINTERS]; #endif int repeat_pict;//解码时有多少个图像被延迟,extra_delay=repeat_pict/(2*fps) int interlaced_frame;//交错帧,表示图像内容是交错的 int top_field_first; int palette_has_changed; int64_t reordered_opaque; int sample_rate;//音频数据的采样率 uint64_t channel_layout;//音频信道布局 AVBufferRef *buf[AV_NUM_DATA_POINTERS]; AVBufferRef **extended_buf; int nb_extended_buf; AVFrameSideData **side_data; int nb_side_data; #define AV_FRAME_FLAG_CORRUPT (1 << 0) #define AV_FRAME_FLAG_DISCARD (1 << 2) int flags; enum AVColorRange color_range; enum AVColorPrimaries color_primaries; enum AVColorTransferCharacteristic color_trc; enum AVColorSpace colorspace;//YUV颜色空间类型 enum AVChromaLocation chroma_location; int64_t best_effort_timestamp; int64_t pkt_pos;//记录上一包输出解码器时Packet的位置 int64_t pkt_duration;//Packet的时长 AVDictionary *metadata; int decode_error_flags; int channels;//音频信道个数 int pkt_size;//Packet的大小 #if FF_API_FRAME_QP attribute_deprecated int8_t *qscale_table; attribute_deprecated int qstride; attribute_deprecated int qscale_type; attribute_deprecated AVBufferRef *qp_table_buf; #endif AVBufferRef *hw_frames_ctx; AVBufferRef *opaque_ref; size_t crop_top; size_t crop_bottom; size_t crop_left; size_t crop_right; AVBufferRef *private_ref; } AVFrame;
8.AVIOContext
协议(文件)操作的顶层结构式AVIOContext,这个对象实现了带缓冲的读/写操作。FFmpeg的输入对象AVFormat的pb字段指向一个AVIOContext。
典型应用如下:
AVFormatContext *ic=NULL; ic=avformat_alloc_context(); unsigned char *iobuffer=(unsigned char*)av_malloc(32768); AVIOContext *avio=avio_alloc_context(iobuffer,32768,0,buffer,fill_iobuffer,NULL,NULL); ic->pb=avio; err=avformat_open_input(&ic,is->filename,is->iformat,&format_opts);
9.URLProtocol
URLProtocol是FFmpeg操作文件的结构(包括文件、网络数据流等),包括open、close、read、write、seek等操作。URLProtocol为协议操作对象,针对每种协议会有一个这样的对象,每个协议操作对象和一个协议对象关联。
10.URLContext
URLContext对象封装了协议对象及协议操作对象,URLContext在avio.c中通过url_alloc_for_protocol进行初始化。并且分配空间(使用av_malloc(sizeof(URLContext)+strlen(filename)+1)函数)。
参考:Android 音视频开发(何俊林 著)