当前位置:   article > 正文

FFMPEG源码之解码数据结构解析_ffmpeg源码解析

ffmpeg源码解析


AVFormatContext

AVFormatContext 结构体在 FFmpeg 库的头文件 libavformat/avformat.h 中有定义。它是 FFmpeg 库中进行媒体文件输入和输出的核心数据结构之一。
AVFormatContext 的主要功能是对媒体文件进行封装格式的处理和管理。它是一个上下文结构,保存了音视频流以及其它附加信息的相关数据和操作。

  1. 媒体文件信息的存储和管理: AVFormatContext 结构体中包含了媒体文件的基本信息,如文件 名、流的数量、文件的时长、格式的元数据等。它的成员变量存储了这些信息,并可以提供方法来访问和修改这些属性。这些信息对于解析和处理媒体文件很重要。
  2. 管理媒体流: AVFormatContext结构体维护了一个AVStream结构体的数组,用于存储和管理媒体文件中的不同流(如视频流、音频流等)。这些 AVStream 结构体包含了每个流的详细信息,如编解码器类型、时基、帧率等。通过操作这些 AVStream 结构体,可以获取和设置流的属性,实现对媒体流的读取和解析。
  3. 打开和关闭媒体文件: AVFormatContext 提供了函数和方法来打开、读取和关闭媒体文件。例如,avformat_open_input() 函数可以打开媒体文件,并初始化 AVFormatContext 结构体的成员变量。avformat_close_input() 可以关闭已打开的文件并释放相关资源。
  4. 解析和检索媒体帧: 通过 AVFormatContext 结构体,可以对媒体文件进行解析和检索。av_read_frame() 函数可以读取下一个媒体帧,并返回相关信息,如帧数据、时间戳等。AVPacket 结构体用于存储解析得到的帧数据。此外,还可以使用 avformat_seek_file() 函数进行随机访问,以定位到指定的时间戳或帧号。
  5. 处理封装格式的特定操作: AVFormatContext 结构体提供了针对不同封装格式的操作。根据封装格式的不同,它可以提供特定的函数和方法,用于读取和写入特定封装格式的头部、元数据处理、流添加和删除等操作。这些操作可以通过访问 AVFormatContext 的成员或调用相关的函数来实现。
  6. 与其他函数和结构的关系: AVFormatContext 结构体与其他函数和结构紧密关联。例如,解码器使用 AVCodecContext 结构体对每个流进行解码,而 AVCodecContext 结构体的一些成员变量可以从 AVStreamAVFormatContext 中获取。另外,解码器使用 AVFormatContext 中的 AVIOContext 结构体来读取媒体文件的数据。

总之,AVFormatContext 是 FFmpeg 库中进行媒体文件输入/输出操作的核心数据结构。它提供了丰富的功能,包括存储和管理媒体文件信息、管理媒体流、打开和关闭媒体文件、解析和检索媒体帧、处理封装格式的特定操作等。与其他函数和结构密切配合,实现了媒体文件的读取、解析和操作的功能。

下面是 AVFormatContext 结构体的一些重要成员变量和函数的详细解释:
AVFormatContext 成员变量:

  • AVInputFormat *iformat:指向 AVInputFormat 结构体的指针,表示输入的媒体文件的封装格式。
  • AVOutputFormat *oformat:指向 AVOutputFormat 结构体的指针,表示输出的媒体文件的封装格式。
  • AVIOContext *pb:指向 AVIOContext 结构体的指针,表示输入或输出的文件 I/O 上下文。
  • AVStream **streams:指向 AVStream 结构体指针数组的指针,表示媒体文件中的所有音频或视频流。
  • int nb_streams:媒体文件中流的数量。
  • int64_t duration:媒体文件的持续时间,以时间基准为单位表示。
  • int64_t bit_rate:媒体文件的比特率,以比特率(bps)为单位表示。
  • int64_t start_time:媒体文件的开始时间,以微秒为单位表示。
  • AVDictionary *metadata:指向 AVDictionary 结构体的指针,用于存储媒体文件的元数据。

AVFormatContext 常用函数:

  • int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options):打开媒体文件并将其信息填充到 AVFormatContext 结构体中。
  • int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options):获取媒体文件中的流信息。
  • int avformat_close_input(AVFormatContext **s):关闭媒体文件并释放相关资源。
  • int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags):在媒体文件中进行时间定位。
  • int av_read_frame(AVFormatContext *s, AVPacket *pkt):从媒体文件中读取一个包并存储在 AVPacket 结构体中。
  • int av_write_frame(AVFormatContext *s, AVPacket *pkt):向媒体文件中写入一个包。

这些是 AVFormatContext 结构体的一些重要成员变量和常用函数。通过操作 AVFormatContext 的成员变量和调用相应的函数,你可以对媒体文件进行读取、写入、定位等操作


AVStream

AVStream 结构体在 FFmpeg 库中的头文件 libavformat/avformat.h 中有定义。AVStream 是用于表示媒体文件中的一个流(例如视频流、音频流等)的结构体。

主要功能包括:

  1. 存储媒体流的基本信息:AVStream 结构体中包含了媒体流的一些基本信息,如流的索引、流的媒体类型(视频、音频等)、流的时基、流的时长等。
  2. 存储编解码器参数:AVStream 结构体中还包含 AVCodecParameters 类型的成员变量,用于存储与该媒体流相关的编解码器参数,如编解码器的类型、编解码器的参数等。
  3. 存储媒体流的帧数据:AVStream 结构体中包含指向媒体帧数据的指针或引用,可以通过访问这些成员变量来获取媒体流中的具体帧数据。
  4. 存储流的时间戳和时间基:通过 AVStream 结构体的成员变量,可以获得流中每个帧的时间戳和时间基,用于控制媒体的播放顺序和同步。
  5. 存储流的元数据和附加信息:AVStream 结构体中还包含了一些成员变量,用于存储媒体流的元数据(如标题、描述、作者等)和附加信息(如字幕、附加流等)。
    AVStream 结构体的功能主要是为了封装和管理媒体文件中的单个流的相关信息和数据,并提供了访问和操作这些信息和数据的接口

以下是 AVStream 结构体的一些重要成员变量及其详细解释:

AVStream 成员变量:

  • int index:流的索引。用于标识不同流的唯一值。
  • int id:对流进行特定标识的整数。用于跟踪流的特殊属性。
  • AVCodecParameters *codecpar:指向 AVCodecParameters 结构体的指针。它包含音频或视频流的编解码器参数,如编解码器类型、采样率、比特率、分辨率等。
  • AVCodecContext *codec:指向 AVCodecContext 结构体的指针。它包含与音频或视频编解码器相关的信息,如编码、解码器类型等。
  • AVRational time_base:流的时间基准。以帧为单位的时间标记的分数形式。用于将时间戳转换为实际时间。
  • int64_t start_time:流的开始时间戳。以时间基准为单位表示。
  • int64_t duration:流的持续时间。以时间基准为单位表示。
  • int64_t bit_rate:流的平均比特率。以比特率(bps)为单位表示。
  • int nb_frames:流中的帧数。
  • AVDictionary *metadata:指向 AVDictionary 结构体的指针,用于存储流的元数据。元数据表示有关流的其他信息,如标题、作者、关键字等。

AVStream 常用函数:

  • int avcodec_parameters_to_context(AVCodecContext *codec, const AVCodecParameters *par):将 AVCodecParameters 的值复制到 AVCodecContext。
  • void avcodec_parameters_from_context(AVCodecParameters *par, const AVCodecContext *codec):将 AVCodecContext 的值复制到 AVCodecParameters。

这些是 AVStream 结构体的一些重要成员变量和常用函数。通过访问 AVStream 的成员变量以及调用相应的函数,你可以获取音频或视频流的详细信息并进行相关处理,比如配置解码器参数、复制参数等。


AVCodecParameters

AVCodecParameters 结构体是 FFmpeg 中用于描述编解码器参数的数据结构之一。它包含了编解码器的参数信息,如编码类型、采样率、编码格式等。下面是 AVCodecParameters 的定义:

typedef struct AVCodecParameters {
    enum AVMediaType codec_type;
    enum AVCodecID codec_id;
    unsigned int codec_tag;
    unsigned int format;
    int bitrate;
    int bits_per_coded_sample;
    int bits_per_raw_sample;
    int profile;
    int level;
    int width;
    int height;
    int channels;
    int sample_rate;
    AVRational sample_aspect_ratio;
    int64_t channel_layout;
    AVDictionary *extradata;
    int64_t start_time;
    int64_t duration;
    int64_t bit_rate;
    int nb_frames;
    AVPixelFormat video_format;
    int video_full_range_flag;
    int color_range;
    int color_primaries;
    int color_trc;
    int color_space;
    int chroma_location;
    int video_delay;
    int64_t channel_layout;
} AVCodecParameters;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

下面是对 AVCodecParameters 结构体中的一些重要字段的功能和操作的详解:
  • codec_type:编解码器的类型(视频、音频等)。
  • codec_id:编解码器的 ID。
  • codec_tag:编解码器的标签。
  • format:编码格式。
  • bitrate:比特率。
  • bits_per_coded_sample:编码样本的每个样本的比特数。
  • bits_per_raw_sample:原始样本(未编码)的每个样本的比特数。
  • profile:编码级别(如 H.264 的 profile)。
  • level:编码级别(如 H.264 的 level)。
  • width:视频帧的宽度。
  • height:视频帧的高度。
  • channels:音频通道数。
  • sample_rate:音频采样率。
  • sample_aspect_ratio:采样长宽比。
  • channel_layout:音频通道布局。
  • extradata:附加的编码器数据。
  • start_time:流的开始时间(以时间基为单位)。
  • duration:流的持续时间(以时间基为单位)。
  • bit_rate:流的比特率。
  • nb_frames:帧的数目。
  • video_format:视频的像素格式。
  • video_full_range_flag:视频是否是全范围。
  • color_range:视频的颜色范围。
  • color_primaries:视频的原色信息。
  • color_trc:视频的色彩转换特性信息。
  • color_space:视频的色彩空间信息。
  • chroma_location:视频的色度位置。

AVCodecParameters 中的这些字段包含了关于编解码器的重要信息,可以用于配置解码器上下文(AVCodecContext)或进行其他与编解码相关的操作。


AVCodec

AVCodec 是 FFmpeg 库中用于音视频编解码的数据结构。它提供了音视频编解码器的实现,并用于对音视频数据进行压缩和解压缩。在 libavcodec/avcodec.h 头文件中定义了 AVCodec 的成员变量和函数。

AVCodec 的主要功能包括:

  1. 编解码器类型:AVCodec 中的 enum AVCodecID codec_id 成员变量指定了编解码器的类型,例如 H.264、AAC、MP3 等。
  2. 编解码器名称和描述:AVCodec 中的 const char *name 和 const char *long_name 成员变量分别表示编解码器的名称和详细描述。
  3. 编解码参数:AVCodec 中的 AVCodecContext *priv_data 成员变量是一个指向 AVCodecContext 结构体的指针,用于存储编解码器的相关参数,如解码器选项、个性化设置等。
  4. 初始化编解码器:AVCodec 提供了 int (*init)(AVCodecContext *) 函数,用于初始化编解码器上下文。
  5. 编码和解码音视频数据:AVCodec 提供了 int (*encode)(AVCodecContext *, AVPacket *, const AVFrame *, int *got_packet_ptr) 和 int (*decode)(AVCodecContext *, AVFrame *, int *got_frame_ptr, const AVPacket *) 函数,分别用于音视频数据的编码和解码。
  6. 编解码器配置:AVCodec 提供了很多编解码器相关的选项,如 int (*set_parameters)(AVCodecContext *, AVCodecParameters *) 函数用于设置编解码器参数,int (*get_buffer)(AVCodecContext *, AVFrame *frame) 函数用于获取编码器需要的输入帧缓冲区。
  7. 销毁编解码器:AVCodec 提供了 void (*close)(AVCodecContext *) 函数,用于销毁编解码器上下文和释放相关资源。

通过 AVCodec 结构体提供的功能,你可以选择合适的编解码器、初始化编解码器上下文、对音视频数据进行编解码等操作。这使得你能够使用 FFmpeg 库对音视频内容进行处理并实现各种应用,如转码、剪辑、流媒体等。


AVCodecContext

AVCodecContext 是 FFmpeg 库中用于音视频编解码的上下文结构体。它包含了音视频编解码的相关参数和状态信息。在 libavcodec/avcodec.h 头文件中定义了 AVCodecContext 的成员变量和函数。

下面是 AVCodecContext 结构体的一些重要成员变量和函数的详细解释:

AVCodecContext 成员变量:

  1. enum AVMediaType codec_type:编解码器的类型,可以是 AVMEDIA_TYPE_AUDIO(音频)或 AVMEDIA_TYPE_VIDEO(视频)。
  2. AVCodec *codec:指向 AVCodec 结构体的指针,表示当前使用的编解码器。
  3. int widthint height:视频帧的宽度和高度。
  4. int sample_rate:音频采样率。
  5. int channels:音频声道数。
  6. int bit_rate:编码器的比特率。
  7. AVRational time_base:时间基准,用于时间戳的转换。
  8. AVDictionary *priv_data:指向 AVDictionary 结构体的指针,用于存储编解码器的私有数据。
  9. AVCodecParameters *codecpar:指向 AVCodecParameters 结构体的指针,包含编解码器的参数。
  10. AVPacket *pkt:指向 AVPacket 结构体的指针,用于存储编码或解码的数据包。

AVCodecContext 常用函数:

  1. int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options):打开编解码器。
  2. int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt):向编码器发送数据包进行编码。
  3. int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame):从解码器接收解码后的音视频帧。
  4. void avcodec_free_context(AVCodecContext **avctx):释放编解码器上下文和相关资源。

这些是 AVCodecContext 结构体的一些重要成员变量和常用函数。通过访问 AVCodecContext 的成员变量以及调用相应的函数,你可以配置编解码器参数、进行音视频数据的编解码操作,并获取编解码器的状态信息。这使得你能够使用 FFmpeg 库进行音视频编解码的各个方面的控制和处理。


AVPacket

AVPacket 是 FFmpeg 中的一个数据结构,用于封装音视频数据以及相关的信息,如时间戳、流索引等。AVPacket 结构体定义在 libavcodec/avcodec.h 头文件中。

AVPacket 的主要成员如下:

  1. uint8_t *data:指向音视频数据的指针。
  2. int size:音视频数据的大小(字节数)。
  3. int64_t pts:显示时间戳(Presentation Time Stamp),用于标识数据在播放时的显示时间。
  4. int64_t dts:解码时间戳(Decoding Time Stamp),用于标识数据在解码时的时间顺序。
  5. int stream_index:数据所属的流的索引号。
  6. int flags:标志位,表示数据包的一些特殊属性。
  7. AVPacketSideData *side_data:指向附加信息的指针,如字幕或其他元数据。
  8. int side_data_elems:附加信息的个数。

AVPacket相关的操作函数如下:

  1. av_packet_alloc:分配一个 AVPacket,返回一个已经初始化的 AVPacket 结构体指针。
  2. av_init_packet:初始化 AVPacket 结构体,将其成员变量设置为默认值。
  3. av_packet_clone:复制一个 AVPacket,包括数据和所有成员变量。
  4. av_packet_free:释放 AVPacket 占用的内存空间。
  5. av_packet_unref:重置 AVPacket 的成员变量,释放数据占用的内存。
  6. av_packet_rescale_ts:重新计算 AVPacket 的时间戳,根据给定的时间基进行缩放。
  7. av_packet_add_side_data:为 AVPacket 添加新的附加信息。
  8. av_packet_shrink_side_data:压缩 AVPacket 的附加信息的存储空间大小。

AVPacket 在音视频处理中起到了重要的角色,用于封装和传递音视频数据以及其相关信息。通过使用 AVPacket 结构体和相关的函数,可以对音视频数据进行处理、传递和管理。


AVFrame

AVFrame 是 FFmpeg 中用于表示音视频帧数据的结构体,用于存储解码后的音视频数据以及相关的信息。AVFrame 的定义在 libavutil/frame.h 头文件中。

AVFrame 的主要成员如下:

  1. uint8_t *data[8]:指向音视频数据平面的指针数组,可以存储多个音视频平面的数据。
  2. int linesize[8]:音视频数据平面的行大小,用于描述每个平面的数据行字节数。
  3. uint8_t **extended_data:指向额外数据的指针,用于存储特殊格式的音视频数据。
  4. int width:帧的宽度。
  5. int height:帧的高度。
  6. int nb_samples:音频帧的采样数。
  7. int format:音视频数据的像素格式或采样格式。
  8. AVRational sample_aspect_ratio:采样率比例,用于正确显示和渲染帧。
  9. int64_t pts:显示时间戳,用于标识帧在播放时的显示时间。
  10. int64_t pkt_pts:输入数据包的显示时间戳。
  11. int64_t pkt_dts:输入数据包的解码时间戳。
  12. AVBufferRef *buf[8]:对应数据平面的缓冲区引用。
  13. AVDictionary *metadata:元数据,用于存储帧的附加信息。

AVFrame 相关的操作函数如下:

  1. av_frame_alloc:分配一个 AVFrame 结构体,并对其进行初始化。
  2. av_frame_free:释放 AVFrame 占用的内存空间。
  3. av_frame_clone:复制一个 AVFrame,包括数据和所有成员变量。
  4. av_frame_unref:重置 AVFrame 的成员变量,释放数据占用的内存。
  5. av_frame_move_ref:移动引用,将一个 AVFrame 的引用移动到另一个。
  6. av_frame_get_buffer:为 AVFrame 的数据平面分配缓冲区。
  7. av_frame_is_writable:检查 AVFrame 是否可写。
  8. av_frame_copy:复制一个 AVFrame,包括数据和部分成员变量。

AVFrame 主要用于存储解码后的音视频数据,并提供了访问和操作帧数据的函数。通过使用 AVFrame 结构体和相关的函数,可以对音视频帧进行处理、访问和管理。


AVDictionary

AVDictionary是FFmpeg中用于存储键值对的数据结构。它用于在多个FFmpeg组件之间传递元数据、选项设置、参数等信息。以下是一些常用的AVDictionary相关函数和用法的详解:

AVDictionary的创建和释放:

  1. AVDictionary *dict = NULL :声明一个AVDictionary指针,并初始化为NULL。
  2. av_dict_alloc(&dict) :动态分配一个AVDictionary结构体。
  3. av_dict_free(&dict) :释放AVDictionary结构体及其内存。
    AVDictionary中键值对的添加和修改:
  4. av_dict_set(&dict, key, value, flags) :将键值对添加或修改到AVDictionary中。其中,key是字符串类型的键,value是字符串类型的值,flags用来控制是否覆盖旧值或合并新值。

AVDictionary中键值对的获取和遍历:

  1. char* value = av_dict_get(dict, key, prev, flags); :根据key从AVDictionary中获取对应的值。prev是一个AVDictionaryEntry指针,用于遍历字典中的键值对。
    while (entry = av_dict_get(dict, “”, entry, AV_DICT_IGNORE_SUFFIX)):通过循环遍历字典中的所有键值对,直到entry为NULL。
  2. entry->key :AVDictionaryEntry结构体的成员变量,用于获取键的值。
  3. entry->value :AVDictionaryEntry结构体的成员变量,用于获取值的值。

AVDictionary相关的Flags:

  1. AV_DICT_IGNORE_SUFFIX :在匹配键时忽略键的后缀,可用于获取一组相关键的值。
    当设置了AV_DICT_IGNORE_SUFFIX标志位后,在使用av_dict_get函数查找键值对时,如果传入的key参数无法完全匹配字典中的键,函数将尝试忽略键的后缀,返回与前缀部分匹配的键值对。
    这个标志位通常用于获取一组相关键的值。例如,假设字典中存在以下键值对:
    “video_codec_name” : “h264”
    “video_width” : “1920”
    “video_height” : “1080”
    如果在不使用AV_DICT_IGNORE_SUFFIX的情况下调用av_dict_get(dict, “video”, NULL, 0),将没有返回值。但当设置了AV_DICT_IGNORE_SUFFIX时,调用av_dict_get(dict, “video”, NULL, AV_DICT_IGNORE_SUFFIX)将返回第一个匹配的键值对"video_codec_name" : “h264”。

  2. AV_DICT_DONT_STRDUP_KEY :在函数内部已经对键和值进行了内存管理,所以不需要复制键。
    当设置了AV_DICT_DONT_STRDUP_KEY标志位后,如果使用av_dict_set 函数添加键值对,函数将不会在内部复制键的字符串,而是直接使用传入的键的地址。这意味着,键的值在AVDictionary中被存储的是指向原始键的指针,而不是复制的副本。
    使用AV_DICT_DONT_STRDUP_KEY标志位需要注意以下几点:
    切勿修改传入的键字符的内存,以避免潜在的问题。
    确保键的字符串保持有效,直到字典被释放或键被删除。
    此标志位在某些情况下可以提高性能,特别是在键的字符串已经有保证不会被修改和销毁的情况下,可以避免不必要的内存复制操作。

  3. AV_DICT_DONT_STRDUP_VAL :在函数内部已经对键和值进行了内存管理,所以不需要复制值。

  4. AV_DICT_DONT_OVERWRITE :只在键不存在时添加键值对,不覆盖已有的键值对。

  5. AV_DICT_APPEND :将值追加到现有键的值列表中。
    AVDictionary的相关函数可以用于处理各种媒体元数据、选项和参数信息。在实际应用中,可以根据需求使用这些函数来操作AVDictionary,以实现元数据配置、参数传递等功能。


AVIOContext

AVIOContext是FFmpeg中用于读取和写入数据的抽象结构。它提供了一种统一的接口,可用于访问文件、网络流或自定义的数据源。AVIOContext结构体定义在 libavformat/avo.h 头文件中

AVIOContext的定义如下:

typedef struct AVIOContext {
    unsigned char *buffer;          // 缓冲区
    int buffer_size;                // 缓冲区大小
    unsigned char *buf_ptr;         // 当前缓冲指针
    unsigned char *buf_end;         // 缓冲结束位置指针
    void *opaque;                   // 用户指定的上下文数据指针
    int64_t (*read_packet)(void *opaque, uint8_t *buf, int buf_size);     // 读取数据的回调函数
    int64_t (*write_packet)(void *opaque, uint8_t *buf, int buf_size);    // 写入数据的回调函数
    int64_t (*seek)(void *opaque, int64_t offset, int whence);            // 定位数据位置的回调函数
    int64_t pos;                    // 当前文件位置
    int eof_reached;                // 是否到达文件结尾
    int write_flag;                 // 写入标志
    ...
} AVIOContext;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

AVIOContext结构中的关键成员包括:

  1. buffer和buffer_size: 用于读取和写入数据的缓冲区及其大小。
  2. buf_ptr和buf_end: 缓冲区的当前指针和结束指针,用于追踪读取或写入的位置。
  3. opaque: 用户指定的上下文数据指针,可用于访问外部数据。
  4. read_packet、write_packet和seek: 用于读取数据、写入数据和定位数据位置的回调函数指针。
  5. pos: 当前文件位置。
  6. eof_reached: 表示是否已到达文件结尾。
  7. write_flag: 指示AVIOContext用于读取还是写入数据。

以下是几个常用的与AVIOContext相关的函数及其用法说明:

  1. avio_alloc_context
AVIOContext *avio_alloc_context(
    unsigned char *buffer,
    int buffer_size,
    int write_flag,
    void *opaque,
    int64_t (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
    int64_t (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
    int64_t (*seek)(void *opaque, int64_t offset, int whence)
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

该函数用于分配并初始化一个AVIOContext结构。

  • buffer和buffer_size:输入/输出缓冲区及其大小。
  • write_flag:指示AVIOContext是用于读取还是写入数据。
  • opaque:用户指定的上下文数据指针。
  • read_packet、write_packet和seek:用于回调的读取数据、写入数据和定位数据位置的函数指针。
  1. avio_open
int avio_open(
    AVIOContext **s,
    const char *url,
    int flags
);
  • 1
  • 2
  • 3
  • 4
  • 5

该函数用于将指定的URL与给定的AVIOContext相关联。

  • s:AVIOContext结构体指针的指针,用于存储创建的AVIOContext结构体。
  • url:要打开的URL。
  • flags:打开URL的标志,如读取、写入等。
  1. avio_read
int avio_read(
    AVIOContext *s,
    unsigned char *buf,
    int size
);
  • 1
  • 2
  • 3
  • 4
  • 5

该函数从AVIOContext中读取数据并将其存储在提供的缓冲区中。

  • s:AVIOContext结构体。
  • buf:存储读取数据的缓冲区。
  • size:要读取的数据大小。
  1. avio_write
int avio_write(
    AVIOContext *s,
    const unsigned char *buf,
    int size
);
  • 1
  • 2
  • 3
  • 4
  • 5

该函数将给定的数据写入到AVIOContext中。

  • s:AVIOContext结构体。
  • buf:要写入的数据。
  • size:要写入的数据大小。
  1. avio_seek
int64_t avio_seek(
    AVIOContext *s,
    int64_t offset,
    int whence
);
  • 1
  • 2
  • 3
  • 4
  • 5

该函数用于更改AVIOContext的当前数据指针位置、定位到指定位置。

  • s:AVIOContext结构体。
  • offset:偏移量。
  • whence:偏移基准,可以是AVSEEK_SIZE、SEEK_SET、SEEK_CUR和SEEK_END。

AVIOContext自定义数据流的实例

  1. 创建自定义数据源
    首先,您需要创建一个自定义的数据源来提供输入数据。自定义数据源可以是内存中的数据,也可以是网络流、实时生成的数据等。您需要确保自定义数据源的数据提供方式满足FFmpeg所需的读取数据的要求。

  2. 创建AVIOContext上下文
    使用avio_alloc_context函数创建一个AVIOContext上下文,将自定义数据源和相关的回调函数关联起来。这些回调函数将负责在需要时读取自定义数据源中的数据。

  3. 以下是创建AVIOContext上下文的示例代码:

unsigned char* custom_data; // 自定义数据源
int custom_data_size; // 自定义数据源的大小

// 读取数据的回调函数
int64_t read_packet(void *opaque, uint8_t *buf, int buf_size) {
    // 从自定义数据源中读取数据到buf
    // 返回读取的字节数,或者返回负值表示出错
    memcpy(buf, custom_data, buf_size);
    custom_data += buf_size;
    custom_data_size -= buf_size;

    return buf_size;
}

AVIOContext *avio_ctx = avio_alloc_context(
    custom_data, // 数据源
    custom_data_size, // 数据源大小
    0, // write_flag,读取数据
    NULL, // 用户指定的上下文数据指针
    read_packet, // 读取数据的回调函数
    NULL, // 写入数据的回调函数
    NULL // 定位数据位置的回调函数
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在这个例子中,我们将自定义的数据源custom_data和数据源大小custom_data_size传递给avio_alloc_context函数,以创建一个AVIOContext带有读取数据的回调函数。

  1. 打开AVFormatContext
    使用avformat_open_input函数打开AVFormatContext。将创建的AVIOContext与AVFormatContext关联,以便读取数据。

以下是打开AVFormatContext的示例代码:

AVFormatContext *format_ctx = avformat_alloc_context();

// 关联AVIOContext
format_ctx->pb = avio_ctx;

// 打开输入文件
int ret = avformat_open_input(&format_ctx, NULL, NULL, NULL);
if (ret < 0) {
    // 打开输入文件失败
    // 错误处理
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这个示例中,我们通过将创建的AVIOContext赋值给format_ctx->pb来将其与AVFormatContext关联。然后使用avformat_open_input函数打开输入文件,传递format_ctx作为参数,以及其他可选的参数。

  1. 处理读取到的数据
    接下来,您可以使用已打开的AVFormatContext来读取从自定义数据源中读取的数据。例如,可以使用av_read_frame函数逐帧读取音视频数据。
AVPacket packet;

// 读取音视频数据帧
ret = av_read_frame(format_ctx, &packet);
if (ret >=0) {
    // 处理读取到的packet
    // ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

完成操作后,要记得释放资源并清理相关内存。
通过以上步骤,您可以自定义数据流并使用avformat_open_input函数读取该数据流。只需确保自定义数据源,正确设置AVIOContext上下文,并与AVFormatContext关联即可。


AVOutputFormat

AVOutputFormat(Audio/Video Output Format)是FFmpeg库中的结构体,用于定义和描述音视频封装格式的输出。它主要用于确定输出格式和配置输出格式的相关属性。

AVOutputFormat的定义如下:

typedef struct AVOutputFormat {
    const char *name;                     // 输出格式名称
    const char *long_name;                // 输出格式全名或描述
    const char *mime_type;                // 输出格式的MIME类型
    const char *extensions;               // 输出格式的文件扩展名
    enum AVCodecID audio_codec;           // 默认的音频编码器ID
    enum AVCodecID video_codec;           // 默认的视频编码器ID
    enum AVCodecID subtitle_codec;        // 默认的字幕编码器ID
    const AVCodecTag * const *codec_tag;  // 音视频编码器标签的指针
    const AVClass *priv_class;            // 私有数据的类
    ...
} AVOutputFormat;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

AVOutputFormat结构体的成员说明如下:
  • name:输出格式的名称,例如 “mp4”、“mov” 等。
  • long_name:输出格式的全名或描述,例如 “MPEG-4 Part 14”。
  • mime_type:输出格式的MIME类型,用于在网络传输中标识文件类型。
  • extensions:输出格式的常见文件扩展名,多个扩展名用逗号分隔,如 “mp4,m4a,m4v”。
  • audio_codec:默认的音频编码器ID,表示输出格式的默认音频编码器,使用- AVCodecID枚举定义的编码器ID。
  • video_codec:默认的视频编码器ID,表示输出格式的默认视频编码器,使用AVCodecID枚举定义的编码器ID。
  • subtitle_codec:默认的字幕编码器ID,表示输出格式的默认字幕编码器,使用AVCodecID枚举定义的编码器ID。
  • codec_tag:音视频编码器标签的指针,用于输出格式和编码器之间的映射关系,通过标签可以选择或排除特定类型的编码器。
  • priv_class:私有数据的类,用于扩展输出格式的特定属性或功能。

功能: AVOutputFormat结构体用于定义支持的音视频输出格式的属性和默认编码器。它提供了以下主要功能:
  • 定义输出格式的名称、全名、MIME类型和常见文件扩展名,方便识别和选择。
  • 设置默认的音频编码器、视频编码器和字幕编码器,以供引用程序在没有指定编码器时使用。
  • 指定音视频编码器标签,用于输出格式和编码器之间的映射。
  • 提供私有数据的类,以便扩展输出格式的特定属性或功能。

操作详解:
  • 查找输出格式:使用av_guess_format()函数,根据文件扩展名或输出格式名称查找匹配的AVOutputFormat结构体。
  • 创建输出上下文:使用avformat_alloc_output_context2()函数,根据指定的输出格式创建一个输出上下文。
  • 配置输出上下文:设置输出上下文的音视频编码器、封装格式参数等。
  • 打开输出文件:使用avio_open2()函数,打开输出文件或流。
  • 写入音视频帧:通过av_interleaved_write_frame()函数将编码后的音视频帧写入输出文件。
  • 写入文件尾:使用av_write_trailer()函数,写入输出封装格式的文件尾部信息。
  • 关闭输出文件:使用avio_closep()函数,关闭输出文件。

以下是一个使用FFmpeg库中AVOutputFormat的简单示例代码:

#include <stdio.h>
#include <libavformat/avformat.h>

int main() {
    AVOutputFormat *outputFormat;
    AVDictionary *options = NULL;
    
    // 根据文件扩展名获取输出格式
    outputFormat = av_guess_format("mp4", NULL, NULL);
    if (!outputFormat) {
        fprintf(stderr, "Unable to find output format.\n");
        return -1;
    }
    
    // 打印输出格式名称和全名
    printf("Format Name: %s\n", outputFormat->name);
    printf("Long Name: %s\n", outputFormat->long_name);
    
    // 设置输出格式的音频编码器、视频编码器和字幕编码器
    outputFormat->audio_codec = AV_CODEC_ID_AAC;
    outputFormat->video_codec = AV_CODEC_ID_H264;
    outputFormat->subtitle_codec = AV_CODEC_ID_NONE;
    
    // 创建输出上下文
    AVFormatContext *outputContext = NULL;
    int ret = avformat_alloc_output_context2(&outputContext, outputFormat, NULL, NULL);
    if (ret < 0) {
        fprintf(stderr, "Unable to allocate output context.\n");
        return -1;
    }
    
    // 设置输出文件名
    char *outputFile = "output.mp4";
    
    // 打开输出文件
    ret = avio_open2(&outputContext->pb, outputFile, AVIO_FLAG_WRITE, NULL, &options);
    if (ret < 0) {
        fprintf(stderr, "Unable to open output file.\n");
        return -1;
    }
    
    // 写入文件头
    ret = avformat_write_header(outputContext, &options);
    if (ret < 0) {
        fprintf(stderr, "Unable to write header to output file.\n");
        return -1;
    }
    
    // ...
    // 在此处可以使用av_interleaved_write_frame()函数写入音视频帧
    // ...
    
    // 写入文件尾
    av_write_trailer(outputContext);
    
    // 关闭输出文件
    avio_closep(&outputContext->pb);
    
    // 释放输出上下文和资源
    avformat_free_context(outputContext);
    
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/901523
推荐阅读
相关标签
  

闽ICP备14008679号