AVPacket,AVFrame,AVStream结构体

------------------------------------全系列文章目录------------------------------------

相互关系

在这里插入图片描述

AVPacket
  • 用于描述压缩编码数据,其可作为输入传递给解码器,或者作为输出传递给编码器。
  • 对于视频,它通常应该包含一个压缩帧。对于音频,它可能包含多个压缩帧。
  • 使用 av_packet_alloc() 分配,使用 av_packet_free() 释放。
/* !!!略有删减 */
typedef struct AVPacket {
    AVBufferRef *buf;
    int64_t pts;			//显示时间戳
    int64_t dts;			//解码时间戳
    uint8_t *data;			//压缩编码数据
    int   	size;			//压缩编码数据大小			
    int   	stream_index;	//用于标识该AVPacket所属的数据流(视频/音频流)
    int   	flags;			//flags为AVPacket的标志,有以下四个取值
    	#define AV_PKT_FLAG_KEY     	0x0001		//包含关键帧
		#define AV_PKT_FLAG_CORRUPT 	0x0002      //数据包内容已损坏
		#define AV_PKT_FLAG_DISCARD 	0x0004		//虽然送由解码器解码,但只是为了保持解码器状态,解码后直接丢弃
		#define AV_PKT_FLAG_TRUSTED 	0x0008		//可靠的数据包
		#define AV_PKT_FLAG_DISPOSABLE 	0x0010		//非参考帧,将直接被解码器丢弃
    AVPacketSideData *side_data;
    int 	side_data_elems;
    int64_t duration;		//持续时间,单位为AVStream->time_base
    int64_t pos;            //在数据流中的字节位置      
    void 	*opaque;		//用户的私人数据,用于扩展
    AVBufferRef *opaque_ref;
    AVRational 	time_base;
} AVPacket;
AVFrame
  • 用于描述解码后的(原始)音频或视频数据,使用 av_frame_alloc() 分配AVFrame,但其中 data[AV_NUM_DATA_POINTERS] 的空间需要自行申请;使用 av_frame_free() 释放。
  • AVFrame通常分配一次,然后重复使用以保存不同的帧数据,使用前需要用 av_frame_unref() 将其重置为原始状态。
/* !!!略有删减 */
typedef struct AVFrame {
#define AV_NUM_DATA_POINTERS 8
    /*解码后的数据,对于packed格式的数据会全部存在data[0]中,对于planar格式的数据会分开存在data[0],data[1]......中*/
    uint8_t *data[AV_NUM_DATA_POINTERS];
    int linesize[AV_NUM_DATA_POINTERS];	//data中一行数据(宽)大小,通常由于数据对齐等原因,会大于图像的宽
    uint8_t **extended_data;			//当如果声道数超过8,需要从此处获取声道数据
    int width, height;					//视频帧的宽高
    int nb_samples;						//表示该音频帧的采样数
    int format;							//该帧格式,enum AVPixelFormat or enum AVSampleFormat
    int key_frame;						//是否为关键帧
    enum AVPictureType pict_type;		//帧的类型:I、P、B......
    AVRational sample_aspect_ratio;		//视频帧宽高比
    int64_t pts;						//显示时间戳
    int64_t pkt_dts;					//从AVPacket中复制来的dts
    int coded_picture_number;
    int display_picture_number;
    int quality;						//帧质量,1为最好,越大质量越差
    void *opaque;						//用户的私人数据,用于扩展
    int repeat_pict;					//用于解码时,表明图像必须延迟多少
    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;							//帧标志,见@ref lavu_frame_flags
    /* 编码时设置MPEG和JPEG */
    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;		//最优估计时间戳,单位为AVStream时间基
    int64_t pkt_pos;					//从已数据编码器的AVPacket中重新排序得到的pos
    int64_t pkt_duration;				//对应AVPacket的duration
    AVDictionary *metadata;				//输入文件的metadata信息,key-value
    int decode_error_flags;				//解码错误标志
#define FF_DECODE_ERROR_INVALID_BITSTREAM   1
#define FF_DECODE_ERROR_MISSING_REFERENCE   2
#define FF_DECODE_ERROR_CONCEALMENT_ACTIVE  4
#define FF_DECODE_ERROR_DECODE_SLICES       8
    int channels;						//音频通道数
    int pkt_size;						//包含frame数据的AVPacket大小
    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;
AVStream
  • 存储音频/视频流信息的结构体
/* !!!略有删减 */
typedef struct AVStream {
    int index;    	//标识数据流类别,如音频流、视频流
    int id;			
    void *priv_data;
    AVRational time_base;	//表示帧时间戳的基本时间单位,可将时间戳转换为以秒为单位的时间
    int64_t start_time;		//数据流第一帧的时间戳,may be undefined (AV_NOPTS_VALUE)
    int64_t duration;		//数据流的持续时间,单位为time_base
    int64_t nb_frames;      //数据流中frame数量,may be unknown
    int 	disposition; 
    enum AVDiscard discard;
    AVRational sample_aspect_ratio;	//样本宽高比,may be unknown(0)
    AVDictionary *metadata;			//输入文件的metadata信息,key-value
    AVRational avg_frame_rate;		//平均帧率
    AVPacket attached_pic;			//附带的图片,比如某些音乐文件的专辑封面
    AVPacketSideData *side_data;
    int            nb_side_data;
    int event_flags;
#define AVSTREAM_EVENT_FLAG_METADATA_UPDATED 0x0001
#define AVSTREAM_EVENT_FLAG_NEW_PACKETS (1 << 1)
    AVRational r_frame_rate;		//真实帧率
    AVCodecParameters *codecpar;	//描述与该数据流关联的编解码器参数
    int pts_wrap_bits;
} AVStream;
  • int disposition; 表示流的标志,标志为AV_DISPOSITION_xxx;如当mp3文件中附带了封面图片,则其将会有视频流,该视频流的disposition标志为AV_DISPOSITION_ATTACHED_PIC;此时该附带的图片即为AVPacket attached_pic; 变量。
示例代码
  • 打印AVStream信息

    void AVstream_info(AVStream *st) {
        printf("\nindex: %d, timebase: %d %d\n", st->index, st->time_base.num, st->time_base.den);
    
        printf("start time: %ld, ", st->start_time);
        printf("nb frames: %ld\n", st->nb_frames);
        printf("duration: %ld, %ld, %ld\n", st->duration, 
                                          st->duration*st->time_base.num/st->time_base.den, 
                                          st->duration*st->time_base.num/st->time_base.den/60);
    
        printf("width : height = %d : %d\n", st->sample_aspect_ratio.num, st->sample_aspect_ratio.den);
    
        printf("avg fps: %d, %d; real fps: %d, %d\n\n", 
                st->avg_frame_rate.num, st->avg_frame_rate.den, 
                st->r_frame_rate.num, st->r_frame_rate.den);
    }
    
  • 打印AVPacket信息

    void AVPacket_info(AVPacket *pkt) {
        printf("\nindex: %d, pts: %ld, dts: %ld\n", pkt->stream_index, pkt->pts, pkt->dts);
        printf("size: %d, pos: %ld, duration: %ld\n", pkt->size, pkt->pos, pkt->duration);   
    }
    
  • 打印AVFrame信息

    void AVFrame_info(AVFrame *af) {
        printf("\nwidth: %d, height: %d, format: %d\n", af->width, af->height, af->format);
        printf("width : height = %d : %d\n", af->sample_aspect_ratio.num, af->sample_aspect_ratio.den);
        printf("key_frame: %d, pict_type: %d\n", af->key_frame, af->pict_type);
        printf("pts: %ld, pkt_dts: %ld, best_effort_timestamp: %ld\n", 
               				af->pts, af->pkt_dts, af->best_effort_timestamp);
        printf("nb_sample: %d, sample_rate: %d, channels: %d, channel_layout: %lu\n", 
                af->nb_samples, af->sample_rate, af->channels, af->channel_layout);
        
    }
    
  • 输出测试视频的AVStream、AVPacket和AVFrame信息

    int main(int argc, char **argv)
    {
        AVFormatContext   *fmt_ctx  = NULL;
        AVPacket          *pkt      = av_packet_alloc(); 
        AVCodec           *vDc, *aDc;
        AVCodecContext    *vDcCtx, *aDcCtx;
        AVFrame           *vf, *af;
        int               ret       = 0;  
        int               cnt       = 5;		//此处以前5个AVPacket为例子
    
        avformat_network_init();
        avformat_open_input(&fmt_ctx, "../../output/test.mp4", NULL, NULL);
        avformat_find_stream_info(fmt_ctx, NULL);
        
        /* 此处预先直到有两个数据流,且stream 0为视频流,stream 1为音频流 */
        AVStream *st1 = fmt_ctx->streams[0];
        AVStream *st2 = fmt_ctx->streams[1];
    
        vDcCtx = avcodec_alloc_context3(NULL);
        aDcCtx = avcodec_alloc_context3(NULL);
        avcodec_parameters_to_context(vDcCtx, st1->codecpar);
        avcodec_parameters_to_context(aDcCtx, st2->codecpar);
        vDc    = avcodec_find_decoder(vDcCtx->codec_id);
        aDc    = avcodec_find_decoder(aDcCtx->codec_id);
        avcodec_open2(vDcCtx, vDc, NULL);
        avcodec_open2(aDcCtx, aDc, NULL);
    
        vf = av_frame_alloc();
        af = av_frame_alloc();
    
        AVstream_info(st1);
        AVstream_info(st2);
    
        while (cnt --) {
            ret = av_read_frame(fmt_ctx, pkt);
            if (ret >= 0) {
                AVPacket_info(pkt);
                if (pkt->stream_index == 0) {
                    if (avcodec_send_packet(vDcCtx, pkt) >= 0) {
                        if (avcodec_receive_frame(vDcCtx, vf) >= 0)
                            AVFrame_info(vf);
                    }
                } else if (pkt->stream_index == 1) {
                    if (avcodec_send_packet(aDcCtx, pkt) >= 0) {
                        if (avcodec_receive_frame(aDcCtx, af) >= 0)
                            AVFrame_info(af);
                    }
                }
            }
        }
    	
        /*此处只释放AVPacket和AVFrame*/
        av_frame_free(vf);
        av_frame_free(af);
        av_packet_free(pkt);
        return 0;
    }
    
  • 输出如下:

    index: 0, timebase: 1 16000
    start time: 368, nb frames: 16181
    duration: 10787328, 674, 11
    width : height = 1 : 1
    avg fps: 2022625, 84276; real fps: 24, 1
    
    index: 1, timebase: 1 44100
    start time: 0, nb frames: 29039
    duration: 29735921, 674, 11
    width : height = 0 : 1
    avg fps: 0, 0; real fps: 0, 0
    
    index: 0, pts: 368, dts: -960
    size: 56269, pos: 48, duration: 666
    
    index: 0, pts: 3040, dts: -304
    size: 15596, pos: 56317, duration: 666
    
    index: 1, pts: 0, dts: 0
    size: 469, pos: 71913, duration: 1024
    
    width: 0, height: 0, format: 8
    width : height = 0 : 1
    key_frame: 1, pict_type: 0
    pts: 0, pkt_dts: 0, best_effort_timestamp: 0
    nb_sample: 1024, sample_rate: 44100, channels: 2, channel_layout: 3
    
    index: 0, pts: 1696, dts: 368
    size: 8305, pos: 72382, duration: 666
    
    width: 1280, height: 720, format: 0
    width : height = 1 : 1
    key_frame: 1, pict_type: 1
    pts: 368, pkt_dts: 368, best_effort_timestamp: 368
    nb_sample: 0, sample_rate: 0, channels: 0, channel_layout: 0
    
    index: 1, pts: 1024, dts: 1024
    size: 470, pos: 80687, duration: 1024
    
    width: 0, height: 0, format: 8
    width : height = 0 : 1
    key_frame: 1, pict_type: 0
    pts: 1024, pkt_dts: 1024, best_effort_timestamp: 1024
    nb_sample: 1024, sample_rate: 44100, channels: 2, channel_layout: 3
    
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值