C/C++编程:libavformat库学习

模块

多路分配器

  • 多路分配器读取媒体文件并将其分割成数据块
  • 一个包包含一个或者多个属于单个基本流的编码帧。在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()设置

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:尝试找到与此流相关的流(例如,在同一程序中);如果没有,则返回-1
  • coder_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)	

功能

  • 对网络库进行全局初始化
  • 这是可选的,不再建议使用
  • 此功能是为了解决较旧的GnuTLSOpenSSL库的安全问题。如果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行定义。

do_exit()ffmpeg_cleanup()main()引用。

av_muxer_iterate

签名

const AVOutputFormat* av_muxer_iterate	(	void ** 	opaque	)	

功能

  • 遍历所有已经注册的复用器
  • 在文件allformats.c的第499行定义。

参数

  • opaque:是一个存储迭代状态的指针。必须指向NULL才能开始迭代。

返回值

  • 当等待完成时,返回NULL或者下一个注册的多路复用器

av_guess_format()show_formats_devices()引用。

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
效果:
在这里插入图片描述

参考

猜你喜欢

转载自blog.csdn.net/zhizhengguan/article/details/115231184