Libavformat (lavf)是用于处理多种媒体容器格式的库。
其主要目的有两个:一是多路分配(demuxing)分离一个流媒体文件成多个组件 ;二是多路复用的反转过程,将提供的数据写进指定容器格式。
其也有一个IO模块,支持多种协议访问数据(例如:file,tcp,http 等等 )。在使用lavf之前,我们需要调用 av_register_all()来注册所用已编译的muxers and demuxer(多路)信号分离器 和协议(protocols).
除非你明确你将不会用到libavformat的网络能力,否则你还要调用 avformat_network_init().
AVInputFormat结构体用来描述一种被支持的输入格式,相反的AVOutputFormat结构体用来描述一种输出格式。你能通过av_iformat_next()和av_oformat_next()函数来递归取得所有的已注册的输入/输出格式。
协议层并不是pubinc API的一部分,因此你只能通过 avio_enum_protocols()来获得被支持协议的名称。
用于muxer和demuxer主要的lavf结构是AVFormatContext,它输出正在被读取或写入的文件的所用信息。相比于大多数libavformat结构,它并不是pubinc API的一部分,因此它不能被分配在堆(stack)上,不能用 av_malloc()分配,而是使用 avformat_alloc_context()(一些像avformat_open_input()也许也能)。
最重要的AVFormatContext包含:
1. AVFormatContext.iformat "input"格式和AVFormatContext.oformat "output"格式:input格式可以自动检测或者用户设置,而"output"格式只能由用户设置。
2. AVFormatContext.streams AVString数组 描述储存于文件的所有初始流。AVStreams数组通常是通过他们的数组下标调用。
3. AVFormatContext.pb I/O 上下文(I/O context),输入(input)可以由lavf打开也可以由用户设置,输出只能由用户设置(除非你正在处理一个 AVFMT_NOFILE格式)。
Lavf允许我们使用 采用机制(avoptions mechan)配置muxers and demuxers。
AVFormatContext提供的一般(独立于格式的)libavformat ,对于一个已分配好的AVFormatContext或者来自avformat_get_class()函数的 AVClass),能通过一个调用 av_opt_next()的用户进程检查这些选项。 只有在AVInputFormat.priv_class /AVOutputFormat.priv_class 相关格式结构为非空的情况下,AVFormatContext.priv_data提供特殊(与格式相关的)选项。
如果它的AVClass非空, 可以从AVFormatContext.pb获取更多选项。看在nesting上关于avoptions 文件的讨论学习如何访问它。
@defgroup lavf_decoding Demuxing
{
demuxers读取一个流媒体文件将其分割成多个数据包。一个AV数据包(AVPacket)包含一个或多个属于单个基本流的已编码的帧(encoded frames),在lavf 接口中,这个过程由avformat_open_input()打开一个文件,av_read_frame()读取单个数据包,最后avformat_close_input()进行清除来表示。
}
@section lavf_decoding_open 打开一个流媒体文件
打开一个文件的最少信息就是文件的URL或者文件名,由avformat_open_input()返回,例如下面的一段代码:
const char * url="in.mp3";
AVFormatContext *s = NULL;
int ret = acformat_open_input(&s,url,NULL,NULL);
if(ret<0)
about();
上述代码试图分配一个AVFormatContext,打开一个指定文件(自动探测格式),读取文件头,导出储存在 s 里的信息。一些格式没有头部或者没有储存足够的信息,因此,建议你调用avformat_find_stream_info()函数,它会尝试读取并解码几帧以找到丢失的信息。
在一些情况下,你可能想通过avformat_alloc_context()函数自己预先分配一个AVFormatContext,在传给avformat_open_input()之前做一些调整。比如,当你想用自定义函数代替lavf internal I/O layer读取输入数据时,就要做这些,通过avio_alloc_context()建立你自己的AVIOContext,通过你的读取回调它,然后设置你的AVFormatContext的 pd字段(pd field)建立新的AVIOContext.
因为打开文件的格式在avformat_open_input()返回前一般是不知道的,所以在预先分配的上下文(context)里设置demuxer的私有选项是不可能的。相反的,选项应该包装在AVDictionary里然后传递给avformat_open_input().
@code
AVDictionary* options = NULL;
av_dict_set(&options,"video_size","640x483",0);
av_dict_set(&options,"pixel_format","rgb24",0);
if(avformat_open_input(&s,url,NULL,&options)<0)
abort();
av_dict_free(&options);
这段代码给demuxer传输了"video_size"和"pixel_format"这两个私人选项。他们将对 rawvideo demuxer有用,否则rawvideo demuxer将不能说明rawvideo数据(data)。假如这种格式产生不同与raw video的数据,这些选项将无法被rawvideo demuxer所识别导致不发使用。这些无法被识别的选项将被返回给选项目录(options dictionary)(识别选项会产生消耗).调用程序恩能够按其所希望的那样处理这种无法识别的选项。
@code
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);
about();
}
在你完成读取文件后,你必须用avformat_close_input()关闭它。这个函数将释放所有和该文件相关的东西。
@section lavf_decoding_read 从打开的文件中读取数据
反复的调用av_read_frame从打开的AVFormatContext读取数据。每次调用假如成功了,会返回包含一个AVStream的解码数据(encoded data)的AV包(AVPacket),由AVPacket.stream_index鉴别。假如调用者希望将包内数据解码,可以将包传递给the libavcodec decoding functions avcodec_decode_video2(), avcodec_decode_audio4() or avcodec_decode_subtitle2()。
AVPacket.pts,AVPacket.dts and AVPacket.duration 定时消息将被设置,如果已知。如果码流(stream)没有提供这些,那么他们也许未设置(即pts/dts的值为AV_NOPTS_VALUE,duration的值为0)。这些定时信息将放在AVStream.time_base 单元中,就是说,他们必须并联时基(timebase)来将自己转换成秒数。
属于当前demuxer的数据包在下次调用av_read_frame()后将变为无效。在下次调用av_read_frame()之前或者要关闭文件时,用户必须用av_free_packet()来释放数据包。
@defgroup metadata_api Public Metadata API
{
当demuxer时,元数据(metadata)API允许libavformat库将元数据标签(matadata tags)导出给客户端程序。相反的,当muxing时它允许客户端程序设置元数据。
在用于lavu_dict "AVDictionary"API的AVFormatContext, AVStream, AVChapter and AVProgram structs中的元数据域中,元数据被导出或者赋值成键值对串(pairs of key/value string),就像所用在ffmpeg中的字符串一样,元数据被设定为UTF-8双字节编码。注意:在大多数情况下,从demuxer导出的元数据不会检查是否对UTF-8编码有效。
应该记住的重要概念:
1. -key是独一无二的,不会出现2个不同的标签的key是一样的。语义上也是这样的,就是说一个demuxer不应该故意产生几个key,这些key字面上不同但语义上相同
-元数据是横向的 ,不是竖向的,它没有子标签。假如你想储存,举例:制片人Alice和演员鲍勃的孩子的电子邮件地址,可以有key=alice_and_bobs_childs_email_address
-一些修饰语可以被应用到标签名上。这是通过按顺序附加一个连字符和修饰名完成的。例如下面列表出列出的情况: foo-eng-sort, not foo-sort-eng。
-语言 - - 一个value被本地化为一特定语言的标签会被附加 the ISO 639-2/B 3-letter 语言编码。
例如: Author-ger=Michael, Author-eng=Mike 而原始/默认语言是不合格的"Author"标签。如果demuxer设置了任何一个解释标签,那么它应该设置一个默认值。
-排序(sorting)- - 一个被用于排序的标签的修改版本将有附加个"-sort"
举例:artist="The Beatles", artist-sort="Beatles, The"
-分路器尝试以一个通用的格式导出元数据,然而并没有通用的格式标签,因为他们储存在一个容器中。
下表列出了通用标签名:
@verbatim
album -- name of the set this work belongs to
album_artist -- main creator of the set/album, if different from artist.
e.g. "Various Artists" for compilation albums.
artist -- main creator of the work
comment -- any additional description of the file.
composer -- who composed the work, if different from artist.
copyright -- name of copyright holder.
creation_time-- date when the file was created, preferably in ISO 8601.
date -- date when the work was created, preferably in ISO 8601.
disc -- number of a subset, e.g. disc in a multi-disc collection.
encoder -- name/settings of the software/hardware that produced the file.
encoded_by -- person/group who created the file.
filename -- original name of the file.
genre -- <self-evident>.
language -- main language in which the work is performed, preferably
in ISO 639-2 format. Multiple languages can be specified by
separating them with commas.
performer -- artist who performed the work, if different from artist.
E.g for "Also sprach Zarathustra", artist would be "Richard
Strauss" and performer "London Philharmonic Orchestra".
publisher -- name of the label/publisher.
service_name -- name of the service in broadcasting (channel name).
service_provider -- name of the service provider in broadcasting.
title -- name of the work.
track -- number of this work in the set, can be in form current/total.
variant_bitrate -- the total bitrate of the bitrate variant that the current stream is part of
@endverbatim
}
packet 函数
1.
分配读取加载的包并且将其段位(fields)初始化为默认值,
参数 size表示加载大小
成功 return>0,否则返回AVERROR_xxx .
int av_get_packet(AVIOContext* s,AVPacket* pkt,int size);
2.
读取数据并将其附加到当前AVPacket内容的后面,类似于strcat这种在数据后面添加数据的作用。如果当前AVPacket的size为0,那么此函数的作用和av_get_packet一样。注意:这里用到了av_grow_packet ,因此涉及了重新分配,造成低效。因此这个函数只应该被用于当没有合适的方法获得包的最终大小时使用。
int av_append_packet(AVIOContext*s ,AVPacket* pkt,int size);
3.
用于处理精确小数点
小数的精确值是
typedef struct AVFrac {
int64_t val, num, den;
} AVFrac;
/**********************************/
以前自己学习ffmepg的时候翻译,有错误的地方期待大家不吝指出啊!! 后面待续..