AVOutputFormat 再分析

AVOutputFormat 结构体

/**
 * @addtogroup lavf_encoding
 * @{
 */
typedef struct AVOutputFormat {
    const char *name;
    /**
     * Descriptive name for the format, meant to be more human-readable
     * than name. You should use the NULL_IF_CONFIG_SMALL() macro
     * to define it.
     */
    const char *long_name;
    const char *mime_type;
    const char *extensions; /**< comma-separated filename extensions */
    /* output support */
    enum AVCodecID audio_codec;    /**< default audio codec */
    enum AVCodecID video_codec;    /**< default video codec */
    enum AVCodecID subtitle_codec; /**< default subtitle codec */
    /**
     * can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER,
     * AVFMT_GLOBALHEADER, AVFMT_NOTIMESTAMPS, AVFMT_VARIABLE_FPS,
     * AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS, AVFMT_ALLOW_FLUSH,
     * AVFMT_TS_NONSTRICT, AVFMT_TS_NEGATIVE
     */
    int flags;

    /**
     * List of supported codec_id-codec_tag pairs, ordered by "better
     * choice first". The arrays are all terminated by AV_CODEC_ID_NONE.
     */
    const struct AVCodecTag * const *codec_tag;


    const AVClass *priv_class; ///< AVClass for the private context

    /*****************************************************************
     * No fields below this line are part of the public API. They
     * may not be used outside of libavformat and can be changed and
     * removed at will.
     * New public fields should be added right above.
     *****************************************************************
     */
    /**
     * The ff_const59 define is not part of the public API and will
     * be removed without further warning.
     */
#if FF_API_AVIOFORMAT
#define ff_const59
#else
#define ff_const59 const
#endif
    ff_const59 struct AVOutputFormat *next;
    /**
     * size of private data so that it can be allocated in the wrapper
     */
    int priv_data_size;

    int (*write_header)(struct AVFormatContext *);
    /**
     * Write a packet. If AVFMT_ALLOW_FLUSH is set in flags,
     * pkt can be NULL in order to flush data buffered in the muxer.
     * When flushing, return 0 if there still is more data to flush,
     * or 1 if everything was flushed and there is no more buffered
     * data.
     */
    int (*write_packet)(struct AVFormatContext *, AVPacket *pkt);
    int (*write_trailer)(struct AVFormatContext *);
    /**
     * A format-specific function for interleavement.
     * If unset, packets will be interleaved by dts.
     */
    int (*interleave_packet)(struct AVFormatContext *, AVPacket *out,
                             AVPacket *in, int flush);
    /**
     * Test if the given codec can be stored in this container.
     *
     * @return 1 if the codec is supported, 0 if it is not.
     *         A negative number if unknown.
     *         MKTAG('A', 'P', 'I', 'C') if the codec is only supported as AV_DISPOSITION_ATTACHED_PIC
     */
    int (*query_codec)(enum AVCodecID id, int std_compliance);

    void (*get_output_timestamp)(struct AVFormatContext *s, int stream,
                                 int64_t *dts, int64_t *wall);
    /**
     * Allows sending messages from application to device.
     */
    int (*control_message)(struct AVFormatContext *s, int type,
                           void *data, size_t data_size);

    /**
     * Write an uncoded AVFrame.
     *
     * See av_write_uncoded_frame() for details.
     *
     * The library will free *frame afterwards, but the muxer can prevent it
     * by setting the pointer to NULL.
     */
    int (*write_uncoded_frame)(struct AVFormatContext *, int stream_index,
                               AVFrame **frame, unsigned flags);
    /**
     * Returns device list with it properties.
     * @see avdevice_list_devices() for more details.
     */
    int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list);
    /**
     * Initialize device capabilities submodule.
     * @see avdevice_capabilities_create() for more details.
     */
    int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps);
    /**
     * Free device capabilities submodule.
     * @see avdevice_capabilities_free() for more details.
     */
    int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps);
    enum AVCodecID data_codec; /**< default data codec */
    /**
     * Initialize format. May allocate data here, and set any AVFormatContext or
     * AVStream parameters that need to be set before packets are sent.
     * This method must not write output.
     *
     * Return 0 if streams were fully configured, 1 if not, negative AVERROR on failure
     *
     * Any allocations made here must be freed in deinit().
     */
    int (*init)(struct AVFormatContext *);
    /**
     * Deinitialize format. If present, this is called whenever the muxer is being
     * destroyed, regardless of whether or not the header has been written.
     *
     * If a trailer is being written, this is called after write_trailer().
     *
     * This is called if init() fails as well.
     */
    void (*deinit)(struct AVFormatContext *);
    /**
     * Set up any necessary bitstream filtering and extract any extra data needed
     * for the global header.
     * Return 0 if more packets from this stream must be checked; 1 if not.
     */
    int (*check_bitstream)(struct AVFormatContext *, const AVPacket *pkt);
} AVOutputFormat;

AVOutputFormat 是 FFmpeg 中用于管理输出文件容器格式的核心结构体,定义了封装(Muxing)行为的关键属性和操作方法14。以下是其核心功能和用法解析:


1. 功能与定义

  • 核心作用
    AVOutputFormat 描述输出容器格式的元数据和操作接口,支持 MP4、FLV、TS 等格式的封装逻辑实现14。
    每个支持的格式对应一个独立的 AVOutputFormat 实例,并以链表形式组织存储14。

  • 结构体定义关键字段

typedef struct AVOutputFormat {
    const char *name;           // 格式短名称(如 "flv")
    const char *long_name;      // 易读的格式全称(如 "FLV (Flash Video)")
    const char *mime_type;      // MIME 类型(如 "video/x-flv")
    const char *extensions;     // 文件扩展名(如 "flv")
    enum AVCodecID audio_codec; // 默认音频编码格式
    enum AVCodecID video_codec; // 默认视频编码格式
    // 函数指针(初始化、写头/数据包/尾部等)
    int (*write_header)(AVFormatContext *);
    int (*write_packet)(AVFormatContext *, AVPacket *);
    int (*write_trailer)(AVFormatContext *);
    // 其他字段(flags、私有数据大小等)
    // ...
} AVOutputFormat;

关键字段说明:

  • name/long_name:标识封装格式类型14;
  • audio_codec/video_codec:指定默认音视频编码格式4;
  • 函数指针(如 write_header):实现格式封装的具体逻辑48。

2. 标志位(flags)

通过 flags 字段控制封装行为,常见值包括:

  • AVFMT_GLOBALHEADER
    要求编码器生成全局头信息(如 H.264 的 SPS/PPS),适用于 MP4 等格式6;
  • AVFMT_VARIABLE_FPS
    允许可变帧率封装,适用于直播流场景6;
  • AVFMT_TS_NONSTRICT
    允许时间戳非严格递增,增强容错性6。

3. 使用场景与示例

3.1 获取输出格式

通过格式名称、文件扩展名或 MIME 类型查找支持的封装器:

AVOutputFormat *fmt = av_guess_format("flv", NULL, NULL); // 获取 FLV 封装器

3.2 初始化封装上下文

将 AVOutputFormat 绑定到 AVFormatContext 并执行封装操作:

 
  
AVFormatContext *oc = NULL;
avformat_alloc_output_context2(&oc, fmt, NULL, "output.flv"); // 分配上下文并关联格式
3.3 自定义格式实现

定义新的封装器需实现 AVOutputFormat 的函数接口。以 FLV 为例:

AVOutputFormat ff_flv_muxer = {
    .name           = "flv",
    .long_name      = "FLV (Flash Video)",
    .mime_type      = "video/x-flv",
    .priv_data_size = sizeof(FLVContext), // 私有数据存储格式特定参数
    .audio_codec    = AV_CODEC_ID_MP3,
    .video_codec    = AV_CODEC_ID_FLV1,
    .write_header   = flv_write_header,   // 自定义头部写入逻辑
    .write_packet   = flv_write_packet,   // 数据包写入逻辑
    // ...
};

4. 与其他组件的关系

  • AVFormatContext
    AVOutputFormat 作为其成员 oformat,驱动封装流程的控制逻辑58;
  • AVCodecContext
    通过 audio_codec/video_codec 关联默认编码器参数,影响流配置4;
  • 私有数据(priv_data
    存储格式特定的上下文信息(如 FLV 的 FLVContext)46。

总结

AVOutputFormat 是 FFmpeg 封装功能的核心,开发者通过配置其字段和函数指针实现不同格式的写入逻辑。实际应用中需结合目标格式的文档和源码(如 FLV、MP4 的实现)调整参数和行为。

AVInputFormat 再分析-CSDN博客

你可能感兴趣的:(ffmpeg)