模块
多路分配器
- 多路分配器读取媒体文件并将其分割成数据块
- 一个包包含一个或者多个属于单个基本流的编码帧。在
lavf API
中,这个过程由avformat_open_input()
函数表示,这个函数用于打开文件,av_read_frame
用于读取单个数据包,最后用avformat_close_input
清除
打开媒体文件
打开文件所需的最少信息是URL
,该URL传递给avformat_open_input()
,如以下代码所示:
const char *url = "file:in.mp3";
AVFormatContext *s = NULL;
int ret = avformat_open_input(&s, url, NULL, NULL);
if (ret < 0)
abort();
上面的代码尝试分配AVFormatContext
,打开指定的文件(自动检测格式)并读取标头,然后将存储在其中的信息导出到s中。某些格式没有标头或在此处没有存储足够的信息,因此建议您调用avformat_find_stream_info
函数,该函数尝试读取和解码一些帧以查找丢失的信息
在某些情况下,您可能希望自己用avformat_alloc_context
预先分配一个AVFormatContext
并对其进行一些调整,然后再将其传递给avformat_open_input
。其中一种情况是,您希望使用自定义函数来读取输入数据,而不是使用lavf内部IO层。为此,使用avformat_alloc_context
创建自己的AVIOContext
,并将读取回调函数传递给它。然后将AVFormatContext的pb字段设置为新创建的AVIOContext。
由于通常在返回avformat_open_input()之后才知道打开文件的格式,因此无法在预分配的上下文中设置解复用器专用选项。相反,应该将选项传递给保证在AVDictionary
中的avformat_open_input
:
AVDictionary *options = NULL;
av_dict_set(&options, "video_size", "640x480", 0);
av_dict_set(&options, "pixel_format", "rgb24", 0);
if (avformat_open_input(&s, url, NULL, &options) < 0)
abort();
av_dict_free(&options);
此代码将专用选项"video_size"和"pixel_format"传递给解复用器。例如,对于原始视频解复用器,它们将是必需的,因为它不知道如何解释原始视频数据。如果结果证明格式与原始视频有所不同,则解复用器将无法识别这些选项,因此将不会应用这些选项。然后,此类无法识别的选项会在选项字典中返回(已使用已识别的选项)。调用程序可以根据需要处理无法识别的选项,例如
AVDictionaryEntry *e;
if (e = av_dict_get(options, "", NULL, AV_DICT_IGNORE_SUFFIX)) {
fprintf(stderr, "Option %s not recognized by the demuxer.\n", e->key);
abort();
}
读完文件后,必须使用avformat_close_input
将其关闭。它将释放与文件关联的所有内容
从打开的文件中读取
通过重复调用av_read_frame
从打开的AVFormatContext中读取数据。每个成功的调用都将返回一个AVPacket
,其中包含一个AVStream
的编码数据,该数据由AVPacket.stream_index
标识。如果调用者希望对数据进行解码,则可以将此包直接传递到libavcodec解码函数avcodec_send_packet
()或avcodec_decode_subtitle2
()。
数据结构
AVFormatContext
- 作用: 格式化IO上下文
const AVClass * av_class
:
- 用于记录日志和AVOptions的类。
- 由avformat_alloc_context()设置。导出(解复用器)私有选项(如果存在
struct AVInputFormat * iformat
:
- 输入容器格式。
- 仅解复用,由avformat_open_input()设置。
struct AVOutputFormat * oformat
:
- 输出容器格式。
- 仅Muxing,必须由调用方在avformat_write_header()之前设置。
void * priv_data
:
- 格式化私人数据。
- 当且仅当iformat / oformat.priv_class不为NULL时,这才是启用AVOptions的结构。
- muxing:
avformat_write_header()
设置 - demuxing:
avformat_open_input()
设置
- muxing:
AVIOContext * pb
:
- IO上下文
- demuxing: :由用户在avformat_open_input()之前设置(然后用户必须手动将其关闭)或由avformat_open_input()设置。
- muxing:由用户在avformat_write_header()之前设置。调用者必须注意关闭/释放IO上下文。
- 如果在iformat / oformat.flags中设置了AVFMT_NOFILE标志,则不要设置此字段。在这种情况下,(解复用器)将以其他方式处理I / O,并且此字段为NULL。
int ctx_flags
:
- 标记信令流属性。
- AVFMTCTX_ *的组合。由libavformat设置。
unsigned int nb_streams
:
- AVFormatContext.streams中的元素数。
- 由avformat_new_stream()设置,不得被任何其他代码修改。
AVStream ** streams
:
- 文件中所有流的列表。
- 新的流是使用avformat_new_stream()创建的。
- demuxing:流是由libavformat在avformat_open_input()中创建的。如果在ctx_flags中设置了AVFMTCTX_NOHEADER,则新的流也可能会出现在av_read_frame()中。
- muxing:流是由用户在avformat_write_header()之前创建的。
- 由libavformat在avformat_free_context()中释放
char * url
:
AVInputFormat
const char * AVInputFormat :: name
- 以逗号分隔的短格式列表。
const char * AVInputFormat :: long_name
- 格式的描述性名称,比名称更易于理解。
int AVInputFormat::flags
- 可以使用标志:AVFMT_NOFILE,AVFMT_NEEDNUMBER,AVFMT_SHOW_IDS,AVFMT_GENERIC_INDEX,AVFMT_TS_DISCONT,AVFMT_NOBINSEARCH,AVFMT_NOGENSEARCH,AVFMT_NO_BYTE_SEEK,AVFMT_SEEK_TO_PTS。
const char* AVInputFormat::extensions
- 如果定义了扩展名,则不会进行任何探测。
- 通常不应该使用扩展名格式猜测,因为它不够可靠
const struct AVCodecTag* const* AVInputFormat::codec_tag
const AVClass* AVInputFormat::priv_class
- 用于私有上下文的AVClass。
const char* AVInputFormat::mime_type
- 以逗号分隔的mime类型列表。
- 它用于在探测时检查匹配的mime类型。
struct AVInputFormat* AVInputFormat::next
int AVInputFormat::raw_codec_id
- 原始多路分配器在此处存储其编解码器ID。
int AVInputFormat :: priv_data_size
- 私有数据的大小,以便可以在包装器中分配它
int(* AVInputFormat::read_probe)(AVProbeData *)
- 告诉给定的文件是否有机会被解析为这种格式。
- 提供的缓冲区保证为AVPROBE_PADDING_SIZE字节大,因此除非您需要更多,否则不必检查该缓冲区。
函数功能
av_find_input_format
签名:
AVInputFormat* av_find_input_format ( const char * short_name )
功能:
- 根据输入格式的简称找到AVInputFormat。
av_probe_input_format
签名:
AVInputFormat* av_probe_input_format ( AVProbeData * pd,int is_opened ) AVInputFormat* av_probe_input_format2 ( AVProbeData * pd,int is_opened,int * score_max ) AVInputFormat* av_probe_input_format3 ( AVProbeData * pd,int is_opened,int * score_ret )
功能:
- 猜测文件格式
参数:
pd
: 要探查的数据is_opened
: 文件是否已经打开;确定是否探测具有AVFMT_NOFILE的多路分配器。score_max
:大于接受检测所需的探针分数,此后将变量设置为实际检测分数。如果分数<= AVPROBE_SCORE_MAX / 4,建议使用更大的探测缓冲区重试score_ret
:最佳检测的分数。
av_probe_input_buffer
签名:
int av_probe_input_buffer2 ( AVIOContext * pb,AVInputFormat ** fmt,const char * url,void * logctx,unsigned int offset,unsigned int max_probe_size ) int av_probe_input_buffer ( AVIOContext * pb,AVInputFormat ** fmt,const char * url,void * logctx,unsigned int offset,unsigned int max_probe_size )
功能:
- 探测字节流以确定输入格式
- 每次探针返回的分数过低时,探针缓冲区的大小都会增加,并会进行另一次尝试。当达到最大探针大小时,将返回得分最高的输入格式
参数:
pb
:要探查的字节流fmt
:输入格式放这里url
:流的网址logctx
:日志上下文offset
:要从中探测的字节流中的偏移量max_probe_size
:最大探测缓冲区大小(默认为0)返回值:
av_probe_input_buffer2
:成功返回分数,否则为负数av_probe_input_buffer
:成功返回0
avformat_open_input
签名:
int avformat_open_input ( AVFormatContext ** ps,const char * url,AVInputFormat * fmt,AVDictionary ** options )
功能:
- 打开输入流并读取header
- 编解码器未打开。流必须使用avformat_close_input()关闭。
参数:
ps
:指向用户提供的AVFormatContext的指针(由avformat_alloc_context分配)。可能是指向NULL的指针,在这种情况下,此函数将分配AVFormatContext并将其写入ps。请注意,用户提供的AVFormatContext将在失败时释放。url
:要打开的流的URL。fmt
:如果为非NULL,则此参数强制使用特定的输入格式。否则,将自动检测格式。options
:包含AVFormatContext和demuxer-private选项的字典。返回时,此参数将被销毁并替换为包含未找到的选项的dict。可能为NULL。返回值:
- 成功时为0,失败时为负AVERROR。
注意:
- 如果要使用自定义IO,请预分配格式上下文并设置其pb字段。
avformat_find_stream_info
签名:
int avformat_find_stream_info ( AVFormatContext * ic,AVDictionary ** options )
功能:
- 读取媒体文件的数据包以获取流信息
- 这对于没有标题的文件格式(例如MPEG)很有用。在MPEG-2重复帧模式的情况下,此功能还可以计算实际帧率。该功能不会更改逻辑文件的位置。被检查的分组可以被缓冲以用于以后的处理。
参数:
ic
:媒体文件句柄options
: 如果为非NULL,则是指向字典的ic.nb_streams长指针数组,其中第i个成员包含与第i个流相对应的编解码器选项。返回时,每本词典将填充未找到的选项。返回值:
- 成功时为>=0,失败时为负AVERROR_xxx
注意:
- 此函数不能保证打开所有编解码器,因此选项在返回时为非空是完全正常的行为。
av_find_best_stream
签名:
int av_find_best_stream ( AVFormatContext * ic, enum AVMediaType type, int wanted_stream_nb, int >related_stream, AVCodec ** decoder_ret, int flags )
功能:
- 在文件中找到“最佳”流。
- 最佳流是根据各种启发式方法确定为最有可能是用户期望的内容。如果解码器参数为非NULL,则av_find_best_stream将为流的编解码器找到默认的解码器;否则,默认为0。找不到解码器的流将被忽略。
参数:
ic
:媒体文件句柄type
:流类型:视频、音频、字幕等wanted_stream_nb
: 用户请求的流编号,或-1(用于自动选择)related_stream
:尝试找到与此流相关的流(例如,在同一程序中);如果没有,则返回-1coder_ret
:如果非NULL,则返回所选流的解码器flags
: 目前尚未定义返回值:
- 如果成功,则返回非负流号;如果找不到找不到请求类型的流,则返回AVERROR_STREAM_NOT_FOUND;如果找到流但没有解码器,则返回AVERROR_DECODER_NOT_FOUND
核心功能
用于查询libavformat功能,分配核心结构等的函数。
avformat_version
签名:
unsigned avformat_version (void)
功能:
- 返回LIBAVFORMAT_VERSION_INT常量
- 文件utils.c第66行的定义。
int main()
{
printf("%d", avformat_version());
}
avformat_configuration
签名:
const char* avformat_configuration ( void )
功能:
- 返回libavformat的构建时配置。
- 文件utils.c第72行的定义。
int main()
{
printf("%s", avformat_configuration());
}
avformat_license
签名:
const char* avformat_license( void )
功能:
- 返回libavformat许可证。
- 文件utils.c第77行的定义。
int main()
{
printf("%s", avformat_license());
}
avformat_network_init
签名:
int avformat_network_init (void)
功能:
- 对网络库进行全局初始化
- 这是可选的,不再建议使用
- 此功能是为了解决较旧的
GnuTLS
和OpenSSL
库的安全问题。如果libavformat
链接到这些库的较新版本,或者如果您不使用它们,则无需调用此函数。否则,您需要先调用此函数,然后再启动使用它们的任何其他线程。- 一旦删除了对较早的GnuTLS和OpenSSL库的支持,该功能将被弃用,并且该功能不再具有任何用途。
- 在文件utils.c的第4993行定义。
例子:
由main.cpp引用
avformat_network_deinit
签名:
int avformat_network_deinit ( void )
功能:
- 撤消由
avformat_network_init
完成的初始化
- 每次调用avformat_network_init之后,仅调用一次。
- 在文件utils.c的第5005行定义。
av_muxer_iterate
签名:
const AVOutputFormat* av_muxer_iterate ( void ** opaque )
功能:
- 遍历所有已经注册的复用器
- 在文件allformats.c的第499行定义。
参数:
opaque
:是一个存储迭代状态的指针。必须指向NULL才能开始迭代。返回值:
- 当等待完成时,返回
NULL
或者下一个注册的多路复用器
av_demuxer_iterate
签名:
const AVInputFormat* av_demuxer_iterate ( void ** opaque )
功能:
avformat_alloc_context
签名:
AVFormatContext* avformat_alloc_context ( void )
功能:
avformat_free_context
签名:
void avformat_free_context ( AVFormatContext * s )
功能:
avformat_get_class
签名:
const AVClass* avformat_get_class ( void )
功能:
获取AVClass的AVFormatContext
示例
metadata.c
地址:http://www.ffmpeg.org/doxygen/4.1/metadata_8c-example.html#a10
目的: 显示如何在应用程序中使用元数据API。
#include <stdio.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
int main(int argc, char **argv)
{
av_register_all();
avformat_network_init();
AVFormatContext *fmt_ctx = NULL;
AVDictionaryEntry *tag = NULL;
int ret;
if(argc != 2){
printf("usage: %s <input_file>\n"
"example program to demonstrate the use of the libavformat metadata API.\n"
"\n", argv[0]);
return 1;
}
//打开输入流并读取标题。
// 参数
// fmt_ctx: 指向用户提供的AVFormatContext的指针
// argv[1]: 要打开的流的URL
// fmt : 如果为非NULL,则此参数强制使用特定的输入格式。否则,将自动检测格式。
// options : 包含AVFormatContext和demuxer-private选项的字典。返回时,此参数将被销毁并替换为包含未找到的选项的dict。可能为NULL。
// 返回值
// 成功时为0,失败是负的AVERROR
// 注意
// 如果使用自定义IO,需要预先分配格式上下文,并设置其pb字段。
ret = avformat_open_input(&fmt_ctx, argv[1], NULL, NULL);
if(ret){
return ret;
}
// 获取具有匹配键的字典条目。
// 返回的输入键或值不得更改,否则将导致未定义的行为。
// 要遍历所有字典条目,可以将匹配键设置为空字符串“”,并设置AV_DICT_IGNORE_SUFFIX标志。
while ((tag = av_dict_get(fmt_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
printf("%s=%s\n", tag->key, tag->value);
avformat_close_input(&fmt_ctx);
return 0;
}
使用: ./ffmpeg_test rtmp://58.200.131.2:1935/livetv/cctv1
效果: