07FFMPEG的AVCodec结构体分析

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;
		}
	}

实际上视频流和音频流的相关信息获取都是一样的,可以使用上面两种方法,非常简单,这里不再多说。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值