------------------------------------全系列文章目录------------------------------------
相互关系
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