07FFMPEG的AVCodec结构体分析
概述:
该结构体位于libavcodec库中的codec.h中。
注意:
非公共区域的字段我可能不会翻译,因为翻译也不知道说什么,还是保留着原文更好。其它的结构体分析同理。
1 AVCodec 结构体
typedef struct AVCodec {
/**
* 编解码器实现的名称。
* 该名称在编码器和解码器之间是全局唯一的(但编码器和解码器可以共享相同的名称)。(即各种编码器名字唯一和各种解码器名字唯一,但是编解码器可以共享名字。)
* 从用户的角度来看,这是找到编解码器的主要方法。
*/
const char *name;
/**
* 编解码器的描述性名称,意味着比名称更易于读懂。
* 应该使用NULL_IF_CONFIG_SMALL()宏来定义它。
*/
const char *long_name;
enum AVMediaType type;
enum AVCodecID id;
/**
* 编解码器的功能(能力)。
* see AV_CODEC_CAP_*
*/
int capabilities;
const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0} (这句话数组有数据还把数组置空???笔者看不懂,所以这里没翻译,并且这些英文也不难,这里参考雷神的翻译:支持帧率的数组(仅视频))
const enum AVPixelFormat *pix_fmts; ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1
const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0
const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1
const uint64_t *channel_layouts; ///< array of support channel layouts(通道布局), or NULL if unknown. array is terminated by 0
uint8_t max_lowres; ///< maximum value for lowres(低分辨率) supported by the decoder
const AVClass *priv_class; ///< AVClass for the private context
const AVProfile *profiles; ///< array of recognized profiles(已识别配置文件数组), or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN}
/**
* 编解码器实现(安装)的组名。
* 这是支持这个编解码器的包装器(wrapper)的一个简短符号名。包装器为编解码器使用某种外部实现,例如外部库,或由操作系统或硬件提供的编解码器实现。
* 如果这个字段是空的,这是一个内置的,libavcodec本地编解码器。
* 如果非空,这将是AVCodec.name在大多数情况下的后缀(通常AVCodec.name的形式为"_")。
*/
const char *wrapper_name;
/*****************************************************************
* 这一行以下的字段都不是公共API的一部分。他们可能不被libavcodec库以外使用并且可以改变和删除随意。
* 新的公共字段应该在正上方添加。
*****************************************************************
*/
int priv_data_size;
#if FF_API_NEXT
struct AVCodec *next;
#endif
/**
* @name Frame-level threading support functions
* @{
*/
/**
* 将必要的上下文变量从上一个线程上下文复制到当前线程上下文。
* 如果未定义,下一个线程将自动启动; 否则,编解码器必须调用ff_thread_finish_setup()。
*
* dst和src将(很少)指向相同的上下文,在这种情况下,应该跳过memcpy。
*/
int (*update_thread_context)(struct AVCodecContext *dst, const struct AVCodecContext *src);
/** @} */
/**
* Private codec-specific defaults.
*/
const AVCodecDefault *defaults;
/**
* 初始化编解码器静态数据,从avcodec_register()调用。
*
* 这不是为耗时的操作准备的,因为它是为每个编解码器运行,而不管正在使用的编解码器。
*/
void (*init_static_data)(struct AVCodec *codec);
int (*init)(struct AVCodecContext *);
int (*encode_sub)(struct AVCodecContext *, uint8_t *buf, int buf_size,
const struct AVSubtitle *sub);
/**
* 编码数据到一个AVPacket。
*
* 参数avctx:codec context。
* 参数avpkt :output AVPacket(可能包含用户提供的缓冲区)。
* 参数[in]frame:AVFrame包含要编码的原始数据。
* 参数[out]got_packet_ptr:got_packet_ptr编码器设置为0或1表示avpkt中返回了一个非空数据包。(encoder sets to 0 or 1 to indicate that a non-empty packet was returned in avpkt.)
* (注:avcodec_decode_video2函数是0解码失败,1解码成功。)
*
* 返回值:0成功,负数失败。
*/
int (*encode2)(struct AVCodecContext *avctx, struct AVPacket *avpkt,
const struct AVFrame *frame, int *got_packet_ptr);
int (*decode)(struct AVCodecContext *, void *outdata, int *outdata_size, struct AVPacket *avpkt);
int (*close)(struct AVCodecContext *);
/**
* 编码API与解耦帧/包数据流。调用此函数来获取一个输出包。它应该调用ff_encode_get_frame()来获取输入数据。
*/
int (*receive_packet)(struct AVCodecContext *avctx, struct AVPacket *avpkt);
/**
* 解码API与解耦的包/帧数据流。调用这个函数来获得一个输出帧。它应该调用ff_decode_get_packet()来获取输入数据。
*/
int (*receive_frame)(struct AVCodecContext *avctx, struct AVFrame *frame);
/**
* 刷新缓冲区。
* 当seeking时被调用。
*/
void (*flush)(struct AVCodecContext *);
/**
* 内部编解码器功能。
* See FF_CODEC_CAP_* in internal.h
*/
int caps_internal;
/**
* 只有Decoding解码才有, 用逗号分隔的位流过滤器(bitstream filters)列表,在解码前应用于数据包。
*/
const char *bsfs;
/**
*指向编解码器支持的硬件配置的指针数组,如果不支持硬件,则为空。 数组以空指针结束。
*
* 用户只能通过avcodec_get_hw_config()访问该字段。
*/
const struct AVCodecHWConfigInternal **hw_configs;
/**
* 支持的codec_tags列表,以FF_CODEC_TAGS_END结束。
*/
const uint32_t *codec_tags;
} AVCodec;
2 AVCodec中重要的成员
const char *name;//编解码器实现的名称。
const char *long_name;//编解码器的描述性名称,意味着比名称更易于读懂。例如我获取的rtsp输入流的一个:"H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"。
enum AVMediaType type;//指明了类型,是视频,音频,还是字幕。
enum AVCodecID id;//该编解码器的ID,不重复。
const AVRational *supported_framerates;//支持帧率的数组(仅视频)。
const enum AVPixelFormat *pix_fmts;//支持的像素格式(仅视频)。
const int *supported_samplerates;//支持的采样率(仅音频)。
const enum AVSampleFormat *sample_fmts;//支持的采样格式(仅音频)。
const uint64_t *channel_layouts;//支持的声道数(仅音频)。
uint8_t max_lowres; //低分辨率的最大值
int priv_data_size;//私有数据的大小。
3 AVCodec中部分成员的代码例子讲解
该AVCodec结构体是编解码器结构体,保持着编解码器自己的信息和编解码时非公共区域的字段。
由于调用avformat_open_input和avformat_find_stream_info并不会给该编解码器开辟空间和初始化,所以必须avcodec_find_decoder该函数初始化(我记得还有两个函数也是可以init该结构体的,但这里不介绍),这一点需要我们注意。
1)name,long_name,type,id,supported_framerates,pix_fmts视频相关的内容
这些获取方法实际上基本是一样的,这里以long_name为例。
//m_video_index为视频流下标,自己获取一下即可
if (m_video_index != -1) {
AVCodecID codecId;
AVCodec *codec = NULL;
//不能通过第一种方法取名字,因为在未调用查找编码器前,编码器是没有被赋值的,会造成非法访问
//1)video_codec_long_name = in_fmt_ctx->streams[video_index]->codec->codec->long_name;
codecId = m_in_fmt_ctx->streams[m_video_index]->codecpar->codec_id;
codec = avcodec_find_decoder(codecId);//找出编解码器,他会帮你自动开辟内存。
if (codec == NULL) {
m_video_codec_long_name = "";//表示没有找到这种编解码器
}
m_video_codec_long_name = codec->long_name;
}
2)supported_samplerates,sample_fmts,channel_layouts音频有关的内容
这些音频的方法都是差不多的,你可以按照上面的方法获取,先遍历流获取对应的流下标,这里给出另一种方法,就是直接在遍历流下标时获取。
//获取视频流音频流的下标
for (int i = 0; i < m_in_fmt_ctx->nb_streams; i++) {
AVStream *inStream = NULL;
inStream = m_in_fmt_ctx->streams[i];
if (inStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
//视频相关
}
if (inStream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
m_audio_index = i;
//这样获取可能为0,最好通过解码后的获取采样率和通道数
m_audio_samplerate = inStream->codec->sample_rate;
m_audio_channels = inStream->codec->channels;
}
}
实际上视频流和音频流的相关信息获取都是一样的,可以使用上面两种方法,非常简单,这里不再多说。