FFMS2 又称 FFmpegSource2,参阅 https://github.com/FFMS/ffms2。
原文:https://github.com/FFMS/ffms2/blob/master/doc/ffms2-api.md
译文:http://www.cnblogs.com/popapa/p/ffms2api.html
采集日期:2018-3-17
FFmpegSource2(FFMS2)是 Libav/FFmpeg 的封装库,并且增加了一些组件来解决 libavformat 格式(曾经)碰到的问题。有了它,你就可以简单地实现:“打开并解压多媒体文件就是了,实现细节不用我操心”,再也不必经常受困于苍白无力的 Libav/FFmpeg API 文档了。运气好的话,你也许还能精确定位到每一帧音视频数据。虽然 FFMS2 库是用 C++ 编写的,但暴露出来的 API 却是 C 格式的,可以直接加入并和纯 C 程序进行链接。
源代码遵守 MIT 协议,可从 GitHub 获取。
功能限制
FFMS2 并不包含封装(mux)或编码功能,也无法让你对编码器进行完整的控制。FFMS2 不会将原始的压缩数据解封出来(demux),你只能获取到已解压的数据。因为在读取每帧音视频数据之前,FFMS2 必须对输入文件建立索引,所以它对实时播放也无法提供合适的解决方案。FFMS2 目前对字幕、附件数据、章节信息都不做处理。FFMS2 的音视频帧读取函数不是线程安全的,同一时刻只能运行一次。
编译方法
FFMS2 依赖于以下库:
-
- 建议的编译参数:
--disable-debug --disable-muxers --disable-encoders --disable-filters --disable-hwaccels --disable-network --disable-devices --enable-runtime-cpudetect
(如果你是在编译正式发布库,那么最好是开启 runtime-cpudetect;如果不关闭 disable-debug,dll 的尺寸将增大很多)。
- 建议的编译参数:
非 Windows 环境下的编译比较简单,如果 FFmpeg 和 zlib 已经安装在默认位置,那么只要按照正常步骤进行即可:./configure、make、make install
。
Windows 环境下编译的注意事项
在 Windows 下编译 FFMS2,会有很多选项。FFmpeg 和 FFMS2 可以都用 MinGW 编译;也可以让 FFmpeg 用 MinGW 编译,而 FFMS2 用 VC++ 编译;或者两者都用 VC++ 编译也行。标准的 Avisynth 2.5 插件体系要求 FFMS2 得用 VC++ 编译才行,而 Avisynth 的 C plugin 体系(支持 Avisynth 2.6)则要求使用 MinGW 编译(选用c_plugin
源码分支)。
如果两者都用 MinGW 编译,目前尚未发现什么问题。如果 FFMS2 用 MinGW 编译、 FFMS2 用 VC++ 编译,则在编译 FFmpeg 时需带上--extra-cflags="-D_SYSCRT"
参数。如果你希望生成静态库,而非共享库(shared library),那就必须手工将已安装的头文件和库位置添加到 VC++ 的搜索路径中去(如果 32 位和64 位库都需要生成,请确保路径的正确性)。
如果两者都用 VC++ 编译,请在 msys 中运行build-win-deps.sh
,以生成所有的依赖资源,然后打开解决方案并开始编译。如果你用的是 Visual Studio 2013 之前的版本,为了能编译 FFmpeg,你的 msys 得带有 c99-to-c89。
快捷用法
如果只想以最简单的方式利用 FFMS2 打开视频文件,不想了解细节,不用选择索引方式,不用报告进度,不用保存索引文件,不用读取关键帧、时间戳之类的信息,那么下面就是最简代码示例。
#include <ffms.h>
int main (...) {
/* 初始化 FFMS 库*/
FFMS_Init(0, 0);
/* 建立索引。这里没有对音频轨建索引。 */
char errmsg[1024];
FFMS_ErrorInfo errinfo;
errinfo.Buffer = errmsg;
errinfo.BufferSize = sizeof(errmsg);
errinfo.ErrorType = FFMS_ERROR_SUCCESS;
errinfo.SubType = FFMS_ERROR_SUCCESS;
const char *sourcefile = "somefilename";
FFMS_Indexer *indexer = FFMS_CreateIndexer(sourcefile, &errinfo);
if (indexer == NULL) {
/* handle error (print errinfo.Buffer somewhere) */
}
FFMS_Index *index = FFMS_DoIndexing2(indexer, FFMS_IEH_ABORT, &errinfo);
if (index == NULL) {
/* 错误处理 */
}
/* Retrieve the track number of the first video track */
int trackno = FFMS_GetFirstTrackOfType(index, FFMS_TYPE_VIDEO, &errinfo);
if (trackno < 0) {
/* 没找到视频轨,这种致命错误必须处理 */
/* 比如可以把错误显示出来 */
}
/* 现在已具备条件创建 VideoSource 对象了 */
FFMS_VideoSource *videosource = FFMS_CreateVideoSource(sourcefile, trackno, index, 1, FFMS_SEEK_NORMAL, &errinfo);
if (videosource == NULL) {
/* 错误处理 */
}
/* 因为在 VideoSource 对象的创建过程中,index 已经复制了一份进去,
现在 index 对象可以被销毁了 */
FFMS_DestroyIndex(index);
/* 读取视频属性信息。
因为参数中没有带 errmsg,所以该函数不会失败。 */
const FFMS_VideoProperties *videoprops = FFMS_GetVideoProperties(videosource);
/* 现在可以好好利用这些视频属性信息,比如获取总帧数 */
int num_frames = videoprops->NumFrames;
/* 尝试读取第 1 帧,这很有必要。
因为分辨率和色彩空间(colorspace)都包含在每帧的数据中,而非全局信息。 */
const FFMS_Frame *propframe = FFMS_GetFrame(videosource, 0, &errinfo);
/* 现在可以按需进行操作了,比如可以读取以下数据:
propframe->EncodedWidth; (当前帧的宽度,单位为像素)
propframe->EncodedHeight; (当前帧的高度,单位为像素)
propframe->EncodedPixelFormat; (当前帧的真实色彩空间)
*/
/* 现在可以修改输出帧的色彩空间,或者改变输出帧的大小。
重点:这么做也是为了应对分辨率和色彩空间在中途发生变化的情况。
可以通过查看 FFMS_Frame 的 Encoded* 属性获取到当前帧的原始分辨率。 */
/* 关于图像格式/色彩空间的定义,请参阅 libavutil/pixfmt.h。
在调用 GetPixFmt 获取图像格式时,只要把 pixfmt.h 里定义的常量去掉 PIX_FMT_ 前缀,并全部小写
比如 PIX_FMT_YUV420P 即变为 “yuv420p”。*/
/* 输出格式数组的最后一个成员应填入 -1,作为结束标志 */
int pixfmts[2];
pixfmts[0] = FFMS_GetPixFmt("bgra");
pixfmts[1] = -1;
if (FFMS_SetOutputFormatV2(videosource, pixfmts, propframe->EncodedWidth, propframe->EncodedHeight,
FFMS_RESIZER_BICUBIC, &errinfo)) {
/* 错误处理 */
}
/* 现在一切就绪,可以读取真正的视频帧数据了。 */
int framenumber = 0; /* 下次对当前视频对象调用 FFMS_GetFrame* 后,才有意义。 */
const FFMS_Frame *curframe = FFMS_GetFrame(videosource, framenumber, &errinfo);
if (curframe == NULL) {
/* 错误处理 */
}
/* 处理当前帧 curframe */
/* 释放资源 */
FFMS_DestroyVideoSource(videosource);
/* 清理 FFMS 库资源 */
FFMS_Deinit();
return 0;
}
够简单了吧!
建立索引
要用 FFMS2 打开多媒体文件,必须首先建立索引。这是为了能获取到关键帧位置、时间戳等信息,以便能实现逐帧检索。
首先得用 FFMS_CreateIndexer 创建一个索引器(indexer)对象,参数是源文件名。调用 FFMS_GetNumTracksI、FFMS_GetTrackTypeI 和 FFMS_GetCodecNameI 函数,可以从 indexer 对象中可以查到一些信息,以便获悉文件中的轨道(track)数量及其类型。通过调用 FFMS_TrackIndexSettings、FFMS_TrackTypeIndexSettings、[FFMS_SetAudioNameCallback][SetAudioNameCallback] 和 FFMS_SetProgressCallback,可以对索引器进行一些配置,比如对哪些轨道需要建立索引。然后就可以调用 FFMS_DoIndexing2 建立索引了。如果想要中止建立索引的过程,可以调用 FFMS_CancelIndexing 函数。FFMS_DoIndexing2 和 FFMS_CancelIndexing 函数都会销毁原有 indexer 对象并释放内存的。
索引创建完成后,可以调用 FFMS_WriteIndex 将索引对象写入磁盘文件。当需要多次打开同一个文件时,这就很有用了,省得每次打开都得重建索引了。特别是在文件很大或者包含了很多音轨时,这能为你节省很多时间。
调用 FFMS_ReadIndex 可以从已有索引文件中读取并创建索引对象。请注意,读取索引文件的 FFMS2 库,必须和写入索引文件的库版本相同。如果读写时的库版本不同,就会报索引不匹配的错误。可以调用 FFMS_IndexBelongsToFile 来校验一下,看看某个索引文件是否和视频文件匹配。
色彩常量(color primaries、color transfer、color matrix)
这些色彩常量定义,均与 ISO/IEC 23001-8_2013 第 7.1-7.3 节相同。为了避免重复,ffms.h 中未再作定义。如有必要,你可以自行复制一份,或者包含 FFmpeg 中的 libavutil/pixfmt.h 文件即可。
API 函数参考
大部分 API 函数都通过 ErrorInfo 参数报错,甚至是只通过它报错。有些函数目前尚不支持报错,但以后也将通过 ErrorInfo 报错。例如:
char errmsg[1024];
FFMS_ErrorInfo errinfo;
errinfo.Buffer = errmsg;
errinfo.BufferSize = sizeof(errmsg);
errinfo.ErrorType = FFMS_ERROR_SUCCESS;
errinfo.SubType = FFMS_ERROR_SUCCESS;
const FFMS_Frame *frame = FFMS_GetFrame(vb, frameno, &errinfo);
/* failure? */
if (frame == NULL) {
printf("failed to get frame number %d, error message: %s", frameno, errinfo.Buffer);
/* ... */
}
你可自行决定为出错信息缓冲区申请多少内存,空间不够时错误信息会被截断。不过,1024 个字节肯定足矣。
FFMS_Init - 初始化 FFMS 库
void FFMS_Init(int Unused, int Unused2);
初始化 FFMS 库。在调用任何 FFMS2 函数之前,本函数必须被调用一次。本函数线程安全,且只会运行一次。
参数
int Unused
本参数已过期,仅留作保证 API//ABI 兼容性。请传入 0。
int Unused2
本参数也已过期,仅留作保证 API//ABI 兼容性。请传入 0。
FFMS_Deinit - 清理 FFMS 库
void FFMS_Deinit()
清理 FFMS2 库占用的资源。当不再调用任何 FFMS2 函数之后,本函数必须被调用一次。本函数线程安全,且只会运行一次。
FFMS_GetLogLevel - 读取 FFmpeg 报错级别
int FFMS_GetLogLevel();
读取 FFmpeg 的日志/报错级别(即向 STDERR 设备输出诊断信息的数量)。如需详细了解返回值的含义,最好是包含 FFmpeg 的 log.h 文件(#include <libavutil/log.h>
),里面有所有常量的定义。也可以将相关的常量定义复制到你自己的代码中,当然这得 FFmpeg 开发组以后不会再做改动才行,可惜他们的任何修改都是无缘无故就会发生的。
FFMS_SetLogLevel - 设置 FFmpeg 报错级别
void FFMS_SetLogLevel(int Level);
设置 FFmpeg 的日志/报错级别,详情请参阅 FFMS_GetLogLevel。
FFMS_CreateVideoSource - 创建视频源对象(VideoSource)
FFMS_VideoSource *FFMS_CreateVideoSource(const char *SourceFile, int Track, FFMS_Index *Index, int Threads, int SeekMode, FFMS_ErrorInfo *ErrorInfo);
用指定参数创建FFMS_VideoSource
对象。FFMS_VideoSource
对象代表着一个视频流,可以传给其他 API 函数用于读取视频帧和元数据(metadata )。该视频流必须是建立过索引的(参阅索引相关函数)。请注意在创建过程中,index 对象会被复制一份传入。因此一旦 VideoSource 对象创建成功,通常就可以立即将 index 对象销毁。index 对象中的所有信息,都可以从FFMS_VideoSource
对象中获取得到。
参数
const char *SourceFile
将要打开的视频源文件。相对路径或绝对路径均可。
int Track
要打开的视频轨编号,该编号也为解封器(demuxer)所用。关于如何判断视频轨编号的详细信息,请参阅 FFMS_GetNumTracks、FFMS_GetTrackType、FFMS_GetFirstTrackOfType 及其变体。
FFMS_Index *Index
指向 FFMS_Index 对象的指针,其中包含了对应视频轨的索引信息。
int Threads
要用来解码的线程数。如果小于 1时,线程数将采用 CPU 的核数。如果 FFmpeg 没有用多线程模式编译,则大于 1 的数值无效。
int SeekMode
合法参数值请参考 FFMS_SeekMode。本参数控制着检索(随机读写)的方式,也影响着帧的精度。最常用的是FFMS_SEEK_NORMAL
。
FFMS_ErrorInfo *ErrorInfo
参见错误处理。
返回值
如果 FFMS_VideoSource 对象创建成功,则返回指向其的指针。如果创建失败,则设置 ErrorMsg 信息并返回 NULL。
FFMS_CreateAudioSource - 创建音频源对象(AudioSource)
FFMS_AudioSource *FFMS_CreateAudioSource(const char *SourceFile, int Track, FFMS_Index *Index, int DelayMode, FFMS_ErrorInfo *ErrorInfo);
功能与 FFMS_CreateVideoSource 一致,创建音频轨对象。其他参数均与FFMS_CreateVideoSource
相同,只是多了一个 DelayMode 参数。
参数
int DelayMode
当音频轨的第一个 PTS 非 0 时,处理方式由本参数设定,也即决定着 FFMS 对音频轨延时的处理方式。合法的参数值为:
- FFMS_DELAY_NO_SHIFT:不做调整,第一个解码出来的音频数据包(audio sample)就是输出的第一个数据包。这可能会导致音视频不同步。
- FFMS_DELAY_TIME_ZERO:音频从时间 0 开始输出。可能会生成输出数据包(音量为 0),也可能不生成。
此处译文存疑,原文为:Samples are created (with silence) or discarded so that sample 0 in the decoded audio starts at time zero.
- FFMS_DELAY_FIRST_VIDEO_TRACK:音频从第 1 条视频轨的第 1 帧开始输出。可能会生成输出数据包(音量为 0),也可能不生成。这是大多数用户期望的结果,也是默认值。
- 大于等于 0 的整数:效果视同
FFMS_DELAY_FIRST_VIDEO_TRACK
,但参数值将被视为视频轨编号,用作输出音频时的参照(如不是视频轨编号则音频源对象会创建失败)。
FFMS_DestroyVideoSource、FFMS_DestroyAudioSource - 销毁视频源、音频源对象
void FFMS_DestroyVideoSource(FFMS_VideoSource *V);
void FFMS_DestroyAudioSource(FFMS_AudioSource *A);
销毁FFMS_VideoSource
、FFMS_AudioSource
对象,释放由 FFMS_CreateVideoSource、FFMS_CreateAudioSource 申请的资源。
FFMS_GetVideoProperties - 获取视频的属性信息
const FFMS_VideoProperties *FFMS_GetVideoProperties(FFMS_VideoSource *V);
从 FFMS_VideoSource 对象中读取该视频的属性信息,并保存到一个 FFMS_VideoProperties 结构中,返回结构的指针。
FFMS_GetAudioProperties - 获取音频的属性信息
const FFMS_AudioProperties *FFMS_GetAudioProperties(FFMS_AudioSource *A);
功能与 FFMS_GetVideoProperties 一致,只是读取的对象是FFMS_AudioSource
。请参阅FFMS_AudioProperties。
FFMS_GetFrame - 读取指定视频帧
const FFMS_Frame *FFMS_GetFrame(FFMS_VideoSource *V, int n, FFMS_ErrorInfo *ErrorInfo);
从指定视频流中读取并解码一个视频帧,并保存到一个FFMS_Frame
结构中,视频流由FFMS_VideoSource
对象指定。如果要设置该帧的色彩空间和分辨率,可以先调用 FFMS_SetOutputFormatV2 进行设置。请注意,本函数非线程安全(同一时刻只能从该FFMS_VideoSource
对象中读取 1 帧),返回的FFMS_Frame
指针是常量指针(const pointer)。
参数
FFMS_VideoSource *V
指向FFMS_VideoSource
对象的指针,即需要从中读取帧数据的视频流。
int n
要读取的视频帧编号。编号从 0 开始,第一帧的编号为 0(不是 1),最后一帧的编号是FFMS_VideoProperties->NumFrames
减去 1。如果帧编号超过视频流的总帧数,或者小于起始帧编号(即为负值),那会导致不可预测的后果。
FFMS_ErrorInfo *ErrorInfo
参见错误处理。
返回值
如果读取成功则返回指向FFMS_Frame
的指针,如果失败则设置ErrorMsg
并返回 NULL。
返回的数据帧由参数给出的FFMS_VideoSource
对象负责管理。如果该视频源对象被销毁,或者从该视频源读取了其他帧,或者输入输出格式发生变化,那么帧数据才会失效。否则帧数据会一直保持有效。请注意,虽然多次调用FFMS_GetFrame
时多半会返回同一个指针,但直接将其作为输出帧是不够安全的,因为有时也会发生重新分配内存的情况。
FFMS_GetFrameByTime - 读取指定时刻的视频帧
const FFMS_Frame *FFMS_GetFrameByTime(FFMS_VideoSource *V, double Time, FFMS_ErrorInfo *ErrorInfo);
功能与 FFMS_GetFrame 一致,只是参数不是帧编号,而是单位为秒的时刻。并且返回与给定时刻最为接近的视频帧。如果你实在是懒得自己建立帧号和时刻之间的映射关系,本函数正是为你准备的。
FFMS_GetAudio - 解码几个音频数据包
int FFMS_GetAudio(FFMS_AudioSource *A, void *Buf, int64_t Start, int64_t Count, FFMS_ErrorInfo *ErrorInfo);
从指定音频流中解码一定数量的数据包,并保存到给定的缓冲区中,音频流由FFMS_AudioSource
对象指定。请注意,本函数非线程安全,同一时刻只能向同一FFMS_AudioSource
对象发起一个解码请求。
参数
FFMS_AudioSource *A
指向FFMS_AudioSource
对象的指针,即要从中读取数据的音频流。
void *Buf
缓冲区指针,用于存放解码后的音频数据。你必须得自行管理缓冲区内存的申请和释放,因此最好是先检查一下 FFMS_AudioProperties,获取采样格式、声道数、声道分布等信息,然后再来确定需要申请多大的缓冲区空间。显然,缓冲区所需内存的计算公式即为:num_bytes = bytes_per_sample * num_channels * num_samples
。
int64_t Start, int64_t Count
需要解码的音频数据范围。参数Count
指定了输出数据包的数量,参数Start
指定了起始位置(含)。正如视频帧编号一样,音频数据包的编号也是从 0 开始,最后一个包的编号则为FFMS_AudioProperties->NumSamples
减去 1。如果指定的范围超过了该音频流最大的音频包编号,或者小于起始编号,那会导致不可预测的后果。
FFMS_ErrorInfo *ErrorInfo
参阅错误处理。
返回值
如果成功则返回 0。如果失败则设置 'ErrorMsg`并返回非 0。
FFMS_SetOutputFormatV2 - 设置视频帧的输出格式
int FFMS_SetOutputFormatV2(FFMS_VideoSource *V, int *TargetFormats, int Width, int Height, int Resizer, FFMS_ErrorInfo *ErrorInfo);
设置输出视频帧的色彩空间和大小,视频源由FFMS_VideoSource
给出。设置完成后,后续对 FFMS_GetFrame 和 FFMS_GetFrameByTime 的调用结果都会收到影响,直至下一次 FFMS_SetOutputFormatV2 或 FFMS_ResetOutputFormatV 调用。你可以随时对输出格式做出调整,不需要重新初始化FFMS_VideoSource
对象,也不需要做其他任何操作。你要愿意的话,甚至可用本函数将视频转成灰度图像(黑白)。如果参数中给出的色彩空间格式(pixelformat)数量超过 1 种,那在之后读取帧数据时,应该检查一下FFMS_Frame
的属性信息,查看一下当前选中的是哪一种格式。切记每读一帧都要检查一下,不然结果会一团糟的。本函数自 2.16.3.0 版本开始引入,取代了FFMS_SetOutputFormatV
。
参数
FFMS_VideoSource *V
指向FFMS_VideoSource
对象的指针,即要改变输出格式的视频流。
int *TargetFormats
输出色彩空间。数组的最后一个元素应为 -1。函数会与当前帧的源色彩空间进行对比,自动选择其中转换损失最小的那一种,作为当前选中格式。如果要了解每个整数值对应的色彩空间,请参阅 FFMS_GetPixFmt。
示例:
int targetformats[3];
targetformats[0] = pixfmt1;
targetformats[1] = pixfmt2;
targetformats[2] = -1;
int Width, int Height
输出的图像大小单位为像素数。如果你不需要改变图像的大小,只要传入视频原始大小即可。传入非法的图像大小(比如 0 或负数),会导致不可预知的结果。
int Resizer
设定图像缩放算法,这里的整数值由枚举FFMS_Resizers
定义。即便你不需要对图像进行缩放,也必须指定一个值,因为视频流的分辨率可能会中途(mid-stream)改变,这时无论如何都会用到本参数。如果某一帧用了不同的分辨率进行解码,你只会得知分辨率发生了变化,却无法干预。当需要缩放色度平面(chroma planes)时,也会用到本参数。
FFMS_ErrorInfo *ErrorInfo
参见错误处理。
返回值
如果设置成功则返回 0,失败则设置ErrorMsg
并返回非 0 值。
FFMS_ResetOutputFormatV - 重置视频输出格式
void FFMS_ResetOutputFormatV(FFMS_VideoSource *V);
重置输出格式,使得后续不做任何图像转换,视频源由FFMS_VideoSource
对象给出。请注意,执行本函数的后果很可能无法预料,特别是当视频流分辨率中途发生变化时。在调用本函数之后,最好是能继续调用一下 FFMS_GetFrame,检查一下各个视频参数,看看是否如愿进行了重置。
FFMS_SetInputFormatV - 覆盖源视频格式
int FFMS_SetInputFormatV(FFMS_VideoSource *V, int ColorSpace, int ColorRange, int PixelFormat, FFMS_ErrorInfo *ErrorInfo);
覆盖已传给 SWScale 的原色彩空间参数,并改变视频帧的大小。在下一次调用 FFMS_SetInputFormatV 或 FFMS_ResetInputFormatV 之前,FFMS_GetFrame 和 FFMS_GetFrameByTime 的结果都持续受到影响。你可以随时改变输入格式,不必重新初始化FFMS_VideoSource
对象或做其他任何操作。本函数主要是供设错 YUV 格式参数的程序使用的,使其能与 RGB 格式进行相互转换。不过当视频文件的色彩空间参数不正确时,本函数也会相当有用。函数不会对传入的参数进行正确性校验,如果想利用本函数让 FFMS2 用 RGB 格式打开一个 YUV 文件,恐怕不会奏效。仅当输出格式是用 FFMS_SetOutputFormatV2 设置时,本函数才会生效。自 2.17.1.0 版本开始引入。
参数
FFMS_VideoSource *V
指向FFMS_VideoSource
对象的指针,即需要改变输出参数的视频流。
int ColorSpace
期望的输入色彩空间值,如为FFMS_CS_UNSPECIFIED
则表示不作改动。参见 FFMS_ColorSpaces。
int ColorRange
期望的输入色域值,如为FFMS_CS_UNSPECIFIED
则表示不作改动。参见 FFMS_ColorRanges。
int PixelFormat
期望的输入像素格式,参见 FFMS_GetPixFmt。FFMS_GetPixFmt("")
则表示像素格式不作改动。
FFMS_ErrorInfo *ErrorInfo
参见错误处理。
返回值
如果设置成功则返回 0,失败则设置ErrorMsg
并返回非 0 值。
FFMS_ResetInputFormatV - 重置视频输入格式
void FFMS_ResetInputFormatV(FFMS_VideoSource *V);
将视频输入格式重置为源文件给出的值,视频源由FFMS_VideoSource
对象给出。
FFMS_DestroyIndex - 销毁索引对象
void FFMS_DestroyFFMS_Index(FFMS_Index *Index);
销毁给出的FFMS_Index
对象,并释放其申请的内存。
FFMS_GetErrorHandling - 获取创建索引时的错误处理模式
int FFMS_GetErrorHandling(FFMS_Index *Index);
返回当时传给 FFMS_DoIndexing2 的 ErrorHandling 参数。
FFMS_GetFirstTrackOfType - 获取第一条指定类型的轨号
int FFMS_GetFirstTrackOfType(FFMS_Index *Index, int TrackType, FFMS_ErrorInfo *ErrorInfo);
检索第一条符合指定类型的轨道,并返回其编号。轨道类型由 FFMS_TrackType 定义,索引由 FFMS_Index 定义。该编号可用于 FFMS_CreateVideoSource 和 FFMS_CreateAudioSource 等 API 函数。
参数
FFMS_Index *Index
指向FFMS_Index
对象的指针,代表要检索的媒体文件。
int TrackType
指定要检索的轨道类型。参见 FFMS_TrackType。
FFMS_ErrorInfo *ErrorInfo
参见错误处理。
返回值
成功时返回轨道编号(大于等于 0 的整数值)。失败则设置ErrorMsg
并返回负数(即未发现指定类型的轨道)。
FFMS_GetFirstIndexedTrackOfType - 获取已索引的第一条指定类型的轨号
int FFMS_GetFirstIndexedTrackOfType(FFMS_Index *Index, int TrackType, FFMS_ErrorInfo *ErrorInfo);
功能与 FFMS_GetFirstTrackOfType 一致,只是会忽略未建索引的轨道。
FFMS_GetNumTracks - 获取索引内的音视频轨总数
int FFMS_GetNumTracks(FFMS_Index *Index);
返回媒体文件中的音视频轨总数,文件由FFMS_Index
类型的索引表示。
FFMS_GetNumTracksI - 获取索引器中的音视频轨总数
int FFMS_GetNumTracksI(FFMS_Indexer *Indexer);
返回媒体文件中的音视频轨总数,文件由FFMS_Indexer
类型的索引器表示。也就是说,功能和 FFMS_GetNumTracks 一致,只是不需要首先对整个文件建立索引了。
FFMS_GetTrackType - 获取轨道的类型
int FFMS_GetTrackType(FFMS_Track *T);
返回指定轨道的类型,返回的整数值由 FFMS_TrackType 定义,轨道由FFMS_Track
对象给出。
FFMS_GetTrackTypeI - 获取轨道的类型
int FFMS_GetTrackTypeI(FFMS_Indexer *Indexer, int Track);
返回轨道的类型,返回的整数值由 FFMS_TrackType 定义。FFMS_Indexer
类型的索引器参数给出了媒体文件,参数Track
则表示其中的轨道编号。也就是说,本函数功能和 FFMS_GetTrackType 一致,只是不需要首先对整个文件建立索引了。如果媒体文件已经建过索引了,那就请换用 FFMS_GetTrackType 吧。因为索引创建完成后,FFMS_Indexer
对象就会被销毁。请注意,如果参数中给出了非法的轨道号,执行结果将不可预料。
FFMS_GetCodecNameI - 获取轨道使用的编码器名称
const char *FFMS_GetCodecNameI(FFMS_Indexer *Indexer, int Track);
返回给定音视频轨使用的编码器名称(即 FFmpeg 定义的“long name”)。FFMS_Indexer
对象给出了媒体文件,参数Track
则表示其中的轨道编号。假如你想弹出菜单让用户选择需要创建索引的轨道,那么本函数就十分有用了。请注意,如果参数中给出了非法的轨道号,执行结果将不可预料。
FFMS_GetFormatNameI - 由索引器获取容器格式名
const char *FFMS_GetFormatNameI(FFMS_Indexer *Indexer);
返回媒体文件所用的容器名称(即 FFmpeg 定义的“long name”)。媒体文件由FFMS_Indexer
对象给出。
FFMS_GetNumFrames - 获取指定轨道的总帧数
int FFMS_GetNumFrames(FFMS_Track *T);
返回指定轨道的总帧数,轨道由FFMS_Track
型参数给出。对于视频轨而言,即总视频帧数,应该颇有用处。对于音频轨而言,则为数据包总数,这几乎毫无用处。因为所有的 API 函数都没用到音频总数据包数。返回 0 表示该轨道尚未建立索引。
FFMS_GetFrameInfo - 获取帧信息
const FFMS_FrameInfo *FFMS_GetFrameInfo(FFMS_Track *T, int Frame);
由索引信息中获取指定帧(由帧号给定)的详细信息,结果以FFMS_FrameInfo
结构的形式给出,FFMS_Track
型的参数指定了已经索引的视频轨。如果FFMS_Track
参数给出的不是视频轨,调用结果将不可预料。
参数
FFMS_Track *T
指向FFMS_Track
对象的指针,即该帧所在的视频轨。
int Frame
需读取信息的帧编号。关于帧号的说明,请参阅 FFMS_GetFrame。如果帧号小于起始帧,或者大于视频轨的总帧数,将会导致不可预料的结果,因此请勿尝试。
FFMS_ErrorInfo *ErrorInfo
参见错误处理。
返回值
成功则返回FFMS_FrameInfo
结构指针。失败则设置ErrorMsg
并返回 NULL。
FFMS_GetTrackFromIndex - 由索引中获取轨道信息
FFMS_Track *FFMS_GetTrackFromIndex(FFMS_Index *Index, int Track);
从FFMS_Index
对象中按轨号读取轨道信息,并保存到FFMS_Track
对象中返回其指针。当你不愿或不能用FFMS_CreateVideoSource
或FFMS_CreateAudioSource
打开某个轨道时,即可使用本函数。如果已经用FFMS_CreateVideoSource
或FFMS_CreateAudioSource
打开过了该轨道,那么更可靠的方式是用FFMS_GetTrackFromVideo
或FFMS_GetTrackFromAudio
。请注意,如果给出非法或不存在的轨道编号,将会导致不可预料的后果,一般是会报内存访问冲突(access violation)的错误。还请注意一点,返回的FFMS_Track
仅在其所属的FFMS_Index
生命周期内才有效。
参数
FFMS_Index *Index
指向FFMS_Index
对象的指针,其中包含了必要的轨道信息。
int Track
轨道编号,对应的解封器也会认到相同的编号(参阅 FFMS_GetNumTracks、FFMS_GetFirstTrackOfType 及其变体函数)。
FFMS_ErrorInfo *ErrorInfo
参见错误处理。
返回值
成功则返回FFMS_Track
指针。请注意,即使该轨道未建立索引也不会报错,只是会返回空的FFMS_Track
。请使用 FFMS_GetNumFrames 查看总帧数是否大于 0,以便了解返回对象是否包含索引之后的数据。
FFMS_GetTrackFromVideo, FFMS_GetTrackFromAudio - 获取音频或视频轨信息
FFMS_Track *FFMS_GetTrackFromVideo(FFMS_VideoSource *V);
FFMS_Track *FFMS_GetTrackFromAudio(FFMS_AudioSource *A);
由FFMS_VideoSource
或FFMS_AudioSource
对象获取轨道的基本信息,返回FFMS_Track
对象指针。一般情况下,这两个函数要比 FFMS_GetTrackFromIndex 更为可靠。因为在给出了不存在的轨道编号时,本函数不会引发访问冲突错误,而是返回不包含索引信息的FFMS_Track
。如果索引对象已被销毁,本函数将返回失效的对象。请注意,返回的FFMS_Track
对象仅在其所属的FFMS_VideoSource
或FFMS_AudioSource
生命周期内才有效。
FFMS_GetTimeBase - 获取视频轨的时基信息(time base)
const FFMS_TrackTimeBase *FFMS_GetTimeBase(FFMS_Track *T);
查找视频轨的基本时间单位,并保存在FFMS_TrackTimeBase
结构中返回其指针,视频轨由FFMS_Track
给出。请注意,本函数仅对视频轨有效。
FFMS_WriteTimecodes - 将视频轨的时间码(timecode)写入磁盘文件
int FFMS_WriteTimecodes(FFMS_Track *T, const char *TimecodeFile, FFMS_ErrorInfo *ErrorInfo);
将视频轨的 Matroska v2 时间码(timecode)写入指定文件,视频轨由FFMS_Track
的参数给出。本函数仅对视频轨有效。
参数
FFMS_Track *T
指向FFMS_Track
对象的指针,即时间码所属的视频轨。
const char *TimecodeFile
文件名。相对路径或绝对路径均可。如果文件已存在,则会清空并覆盖。
FFMS_ErrorInfo *ErrorInfo
参见错误处理。
返回值
成功则返回 0。失败则设置ErrorMsg
并返回非 0。
FFMS_CreateIndexer - 对媒体文件创建索引器对象
FFMS_Indexer *FFMS_CreateIndexer(const char *SourceFile, FFMS_ErrorInfo *ErrorInfo);
对媒体文件创建FFMS_Indexer
对象并返回其指针,文件名由SourceFile
给出。关于如何使用索引器的详细信息,请参阅创建索引。本函数基本就是FFMS_CreateIndexerWithDemuxer(SourceFile, FFMS_SOURCE_DEFAULT, ErrorInfo)
的简化版。
返回值
成功时返回指向FFMS_Indexer
的指针。失败则设置ErrorMsg
并返回 NULL。
FFMS_DoIndexing2 - 对由索引器指定的媒体文件建立索引
FFMS_Index *FFMS_DoIndexing2(FFMS_Indexer *Indexer, int ErrorHandling, FFMS_ErrorInfo *ErrorInfo);
对媒体文件建立索引,返回FFMS_Index
对象,文件由传入的索引器给出。关于建立索引的详细信息,请参阅建立索引一节。请注意,无论索引是否成功建立,本函数均会销毁原FFMS_Indexer
对象并释放由 FFMS_CreateIndexer 分配的内存。
参数
FFMS_Indexer *Indexer
需要建立索引的索引器。索引器对象由 FFMS_CreateIndexer 创建,并可由 FFMS_TrackIndexSettings、FFMS_TrackTypeIndexSettings、FFMS_SetAudioNameCallback
、SetAudioNameCallback
和 FFMS_SetProgressCallback 进行参数配置。
int ErrorHandling
决定了音频解码时的错误处理方式。此处可填入的参数值,参见 FFMS_IndexErrorHandling,最佳默认值是FFMS_IEH_STOP_TRACK
。如果音轨启用了转储(dump)模式,那么解码出错后必定会导致索引创建失败,本参数将会失效。
FFMS_ErrorInfo *ErrorInfo
参见错误处理。
返回值
成功时返回创建完成的FFMS_Index
指针。失败则设置ErrorMsg
并返回 NULL。
FFMS_TrackIndexSettings - 对轨道启用或禁用索引
void FFMS_TrackIndexSettings(FFMS_Indexer *Indexer, int Track, int Index, int Dump);
启用或禁用索引。对于音轨而言,则是启用或禁用索引创建过程中的已解码数据转储。
参数
FFMS_Indexer *Indexer
索引器。
int Track
轨号。
int Index
非 0 表示启用索引,0 则表示禁用索引。默认情况下,视频轨均启用索引,而所有音频轨则禁用。
int Dump
目前未启用。
默认情况下,不会对任何轨道进行转储。
FFMS_TrackTypeIndexSettings - 对某一类轨道全部启用或禁用索引
void FFMS_TrackTypeIndexSettings(FFMS_Indexer *Indexer, int TrackType, int Index, int Dump);
功能和 FFMS_TrackIndexSettings 类似,只是一次对一类轨道做全体配置。
FFMS_SetProgressCallback - 设置更新索引进度用的回调函数
void FFMS_SetProgressCallback(FFMS_Indexer *Indexer, TIndexCallback IC, void *ICPrivate);
在索引创建过程中,FFMS2 会定时调用这里给定的进度回调函数,以报告索引创建进度,你还可以有机会中止索引的创建过程。
回调函数应为以下格式:
int FFMS_CC FunctionName(int64_t Current, int64_t Total, void *ICPrivate);
回调函数的参数说明如下:
int64_t Current
、int64_t Total
- 索引的进度指示(已完成帧数/总帧数)。void *Private
- 与传给FFMS_SetProgressCallback
的Private
参数为同一个指针,用途由你决定。比如在图形用户界面程序中,可用于传入进度条对象,以便在调用索引函数时更新进度。
回调函数返回 0 表示期望继续进行索引,返回非 0 则表示要取消索引过程。返回非 0 将会导致 FFMS_DoIndexing2 失败,失败原因是“用户取消索引的创建”(indexing cancelled by user)。
FFMS_CancelIndexing - 销毁索引器对象
void FFMS_CancelIndexing(FFMS_Indexer *Indexer);
销毁给定的FFMS_Indexer
对象,并释放原来由 FFMS_CreateIndexer 分配的内存。
FFMS_ReadIndex - 从磁盘读取索引文件
FFMS_Index *FFMS_ReadIndex(const char *IndexFile, FFMS_ErrorInfo *ErrorInfo);
从文件中读取索引信息,文件名由IndexFile
给出,绝对路径或相对路径均可。
成功则返回FFMS_Index
,失败则设置ErrorMsg
并返回 NULL。
FFMS_ReadIndexFromBuffer - 从用户缓冲区中读取索引
FFMS_Index *FFMS_ReadIndexFromBuffer(const uint8_t *Buffer, size_t Size, FFMS_ErrorInfo *ErrorInfo);
从用户自定义缓冲区中读取索引数据,缓冲区由Buffer
给出,读取长度为Size
。
成功则返回FFMS_Index
,失败则设置ErrorMsg
并返回 NULL。
FFMS_IndexBelongsToFile - 检测索引和媒体文件是否匹配
int FFMS_IndexBelongsToFile(FFMS_Index *Index, const char *SourceFile, FFMS_ErrorInfo *ErrorInfo);
检测FFMS_Index
是否为SourceFile
文件的索引,虽然采用的是启发式的猜测,但可信度很高。可用于判断 FFMS_ReadIndex 读取的索引对象与某个媒体文件是否相关。否则只有两种方法能判断索引文件和媒体文件是否匹配,一是完全信任用户的操作,二是比较文件名,两者都不大可靠。
参数
FFMS_Index *Index
索引对象。
const char *SourceFile
媒体文件。
返回值
如果索引和媒体文件匹配,返回 0。否则设置ErrorMsg
并返回非 0。
FFMS_WriteIndex - 将索引对象写入磁盘
int FFMS_WriteIndex(const char *IndexFile, FFMS_Index *TrackIndices, FFMS_ErrorInfo *ErrorInfo);
将索引信息写入索引文件,索引对象为FFMS_Index
类型,索引文件名由IndexFile
给出。文件名可以是绝对路径或相对路径,如果文件已存在则会被清空并覆盖。
成功时返回 0,失败则设置ErrorMsg
并返回非 0。
FFMS_WriteIndexToBuffer - 将索引对象写入内存
int FFMS_WriteIndexToBuffer(uint8_t **BufferPtr, size_t *Size, FFMS_Index *Index, FFMS_ErrorInfo *ErrorInfo)
将索引信息写入内存缓存区,并将BufferPtr
指向该缓冲区。索引对象为FFMS_Index
类型,参数Size
为返回的缓冲区大小。该缓冲区必须通过 FFMS_FreeIndexBuffer 进行释放。
成功时返回 0,失败则设置ErrorMsg
并返回非 0。
FFMS_FreeIndexBuffer - 释放由FFMS_WriteIndexToBuffer
分配的缓冲区内存
void FFMS_FreeIndexBuffer(uint8_t **BufferPtr)
释放BufferPtr
指向的缓冲区内存,并将其设为 NULL。
FFMS_GetPixFmt - 由色彩空间名称获取其编号
int FFMS_GetPixFmt(const char *Name);
将色彩空间/像素格式的名称转换为对应的整数常量值,以便用于 FFMS_SetOutputFormatV2,详见其函数说明。有了本函数,你就不必每次写程序时都去包含 FFmpeg 的相关头文件了。关于色彩空间名称的完整清单,请参阅libavutil/pixfmt.h
文件。在给出名称时,需要去除PIX_FMT_
前缀,并全部转换为小写字母。比如PIX_FMT_YUV420P
就写为yuv420p
。因为本函数可以保证获取到正确的常量定义,也就是与编译 FFMS 时的 FFmpeg 版本一致,所以强烈建议你使用本函数,请不要再直接包含pixfmt.h
文件了。
参数
const char *Name
色彩空间/像素格式的名称,应为空字符结尾的 ASCII 字符串。
返回值
成功时返回对应的整数常量。失败(未找到匹配的色彩空间)则返回PIX_FMT_NONE
对应的编号(即 -1)。但请注意,执行FFMS_GetPixFmt("none")
也可返回PIX_FMT_NONE
,严格来说这并不表示调用失败。
FFMS_GetVersion - 返回 FFMS_VERSION 常量
int FFMS_GetVersion();
返回ffms.h
中定义的FFMS_VERSION
整数常量。
数据结构
常用的公共数据结构有以下几种。
FFMS_Frame
typedef struct {
const uint8_t *Data[4];
int Linesize[4];
int EncodedWidth;
int EncodedHeight;
int EncodedPixelFormat;
int ScaledWidth;
int ScaledHeight;
int ConvertedPixelFormat;
int KeyFrame;
int RepeatPict;
int InterlacedFrame;
int TopFieldFirst;
char PictType;
int ColorSpace;
int ColorRange;
int ColorPrimaries;
int TransferCharateristics;
int ChromaLocation;
int HasMasteringDisplayPrimaries;
double MasteringDisplayPrimariesX[3];
double MasteringDisplayPrimariesY[3];
double MasteringDisplayWhitePointX;
double MasteringDisplayWhitePointY;
int HasMasteringDisplayLuminance;
double MasteringDisplayMinLuminance;
double MasteringDisplayMaxLuminance;
int HasContentLightLevel;
unsigned int ContentLightLevelMax;
unsigned int ContentLightLevelAverage;
} FFMS_Frame;
视频帧结构。字段说明如下:
uint8_t *Data[4]
- 指向各图像平面数据的指针数组(存放实际像素数据)。平面(planar)格式使用一个以上的平面(plane),比如 YV12 格式的 Y、U、V 分量各自占用了一个平面。打包(packed)格式则只用到了第一个平面,比如各种的 RGB32 格式。如果要确认一下第 i 个平面是否包含数据,判断方法可以是FFMS_Frame->Linesize[i] != 0
。int Linesize[4]
- 整数数组,存储着 4 个图像平面的扫描线(scan line)长度,单位为字节数。换句话说,就是每个图像平面内的数据分隔单位(pitch)。通常,i 平面内的数据总长为FFMS_Frame->Linesize[i] * FFMS_VideoProperties->Height
,但是请务必小心,某些格式(尤其是 YV12)带有纵向色度分量,U/V 平面的高度可能会和主平面不一样。本字段内的数据还有可能是负值,表示图像在内存中是上下倒置存放的,Data
实际上指向的是最底下一行的数据。通常不需要操心上述情况,只要正操操作一般就没有问题。int EncodedWidth
、int EncodedHeight
- 原始分辨率(单位为像素),也即压缩文件里保存的未经缩放的分辨率。请注意,一个数据流不一定所有帧都是相同的分辨率。int EncodedPixelFormat
- 原始像素格式,即压缩文件里保存的编码格式。int ScaledWidth
、int ScaledHeight
- 输出分辨率(单位为像素),即Data
字段内图像数据的实际分辨率。如果未经缩放则设为 -1。int ConvertedPixelFormat
- 输出像素格式,即Data
字段内图像数据的实际格式。-int KeyFrame
- 如果本帧是关键帧,则为非 0。否则为零。int RepeatPict
- RFF 参数,也即显示时间应为1+RepeatPict
个时基单位。这里的时基单位是 RFF 专用的,在FFMS_VideoProperties->RFFDenominator
和FFMS_VideoProperties->RFFNumerator
中给出。请注意,如果最终采用了本参数作为时间基准,那就得放弃通常的时间计算规则(由FFMS_TrackTimeBase
和帧PTS
得出),因为这两个参数与 RFF 参数基本是不兼容的。int InterlacedFrame
- 非 0 表示本帧是隔行编码的,否则为 0。int TopFieldFirst
- 非 0 表示本帧是奇数场优先,为 0 则表示偶数场优先。仅当InterlacedFrame
字段非 0 时,本字段才有意义。char PictType
- 以单个字符表示的帧压缩类型(I/B/P 等)。关于各种字母的不同含义,请参阅常量和预处理标志一节。int ColorSpace
- YUV 色彩参数。定义与 MPEG-2 规范一致,参见 FFMS_ColorSpaces 枚举。int ColorRange
- 亮度范围。参见 FFMS_ColorRanges 枚举定义。int ColorPrimaries
- 色域值。int TransferCharateristics
- 转换特性。int ChromaLocation
- 色度位置,由 FFMS_ChromaLocations 定义。int HasMasteringDisplayPrimaries
- 非 0 则会设置以下 4 个字段。double MasteringDisplayPrimariesX[3]
- 主平面的 RGB 色彩坐标(X 轴)。double MasteringDisplayPrimariesY[3]
- 主平面的 RGB 色彩坐标(Y 轴)double MasteringDisplayWhitePointX
- 主平面的白场坐标(X 轴)。double MasteringDisplayWhitePointY
- 主平面的白场坐标(Y 轴)。int HasMasteringDisplayLuminance
- 如果非 0 则会设置以下 2 个字段。double MasteringDisplayMinLuminance
- 主平面的最小亮度(单位 cd/m^2)。double MasteringDisplayMaxLuminance
- 主平面的最大亮度(单位 cd/m^2)。int HasContentLightLevel
- 如果非 0 则会设置以下 2 个字段。unsigned int ContentLightLevelMax
- 最大亮度(单位 cd/m^2)。unsigned int ContentLightLevelAverage
- 平均亮度(单位 cd/m^2)。
FFMS_TrackTimeBase
typedef struct {
int64_t Num;
int64_t Den;
} FFMS_TrackTimeBase;
基本时间单位,这是一个比值(rational number),Num
是分子,Den
是分母。请注意,对于某些 CFR 视频轨而言,本值有时会和1/帧率
相同,但实际上与帧率没什么太大关系,千万别以为帧率和本值有关。
FFMS_FrameInfo
typedef struct {
int64_t PTS;
int RepeatPict;
int KeyFrame;
} FFMS_FrameInfo;
视频帧的基本元信息。字段说明如下:
int64_t PTS
- 解码后的时间戳(timestamp)。如果要将本时间戳转换为实际的时钟时间,可以采用以下公式:int64_t timestamp = (int64_t)((FFMS_FrameInfo->PTS * - FFMS_TrackTimeBase->Num) / (double)FFMS_TrackTimeBase->Den)
。int RepeatPict
- RFF 标志。含义与 FFMS_Frame 中的相同。int KeyFrame
- 非 0 表示为关键帧,否则为 0。
FFMS_VideoProperties
typedef struct {
int FPSDenominator;
int FPSNumerator;
int RFFDenominator;
int RFFNumerator;
int NumFrames;
int SARNum;
int SARDen;
int CropTop;
int CropBottom;
int CropLeft;
int CropRight;
int TopFieldFirst;
int ColorSpace; // [已过时]
int ColorRange; // [已过时]
double FirstTime;
double LastTime;
int Rotation;
int Stereo3DType;
int Stereo3DFlags;
double LastEndTime;
int HasMasteringDisplayPrimaries;
double MasteringDisplayPrimariesX[3];
double MasteringDisplayPrimariesY[3];
double MasteringDisplayWhitePointX;
double MasteringDisplayWhitePointY;
int HasMasteringDisplayLuminance;
double MasteringDisplayMinLuminance;
double MasteringDisplayMaxLuminance;
int HasContentLightLevel;
unsigned int ContentLightLevelMax;
unsigned int ContentLightLevelAverage;
} FFMS_VideoProperties;
视频轨的基本信息(元数据)。字段说明如下:
int FPSDenominator; int FPSNumerator;
- 标称(nominal)帧率,以比值的形式给出。对于 Matroska 格式的文件而言,本值根据平均帧率得出,其他格式则均由第一帧的时长而得。请勿用本值来估算每帧的实际时间戳,这只是看上去很美,但会让你无法对可变帧率做出正确的处理。现实很残酷,本值只能在显示基本信息时用用,恐怕只有对 AVI 这种古老的封装格式才会有点准确。一般情况下,本值没什么实用价值,请用FFMS_FrameInfo->PTS
来单独生成每帧的时间戳。int RFFDenominator; int RFFNumerator;
- RFF 时间戳,以比值的形式给出。详情请参阅 FFMS_Frame 中的RepeatPict
字段。int NumFrames
- 视频轨的总帧数。int SARNum; int SARDen;
- 视频帧的长宽比,为比值格式,SARNum
是分子,SARDen
是分母。请注意,尽管你可以完全忽略本值,但如果想正常显示失真的源画面,就用得上了本值了。换句话说,当用户不想参照画面的原始比例时(比如编码时),你可以选择忽略本参数。int CropTop; int CropBottom; int CropLeft; int CropRight;
- 裁剪后的画面长度和宽度。请注意,和 SAR 类似,这也是允许你忽略的参数。但如果你想保证画面 100% 显示正确,还是应该使用能够本值。int TopFieldFirst
- 非 0 表示奇数场优先,为 0 则表示偶数场优先。int ColorSpace
- YUV 色彩参数。定义与 MPEG-2 规范一致,参见 FFMS_ColorSpaces 枚举。你应该选用 FFMS_Frame 中的ColorSpace
字段,因为每个帧的色彩参数可能会不同,除非你已用 FFMS_SetOutputFormatV2 设为同一个固定值。int ColorRange
- 亮度范围。参见 FFMS_ColorRanges 枚举定义。你应该选用 FFMS_Frame 中的ColorRange
字段,因为每个帧的亮度范围可能会不同,除非你已用 FFMS_SetOutputFormatV2 设为同一个固定值。double FirstTime; double LastTime;
- 第一帧和最后一帧的时间戳,单位为秒。如果想知道是否存在延时,或者大致了解总的时长,本字段会有点用处。int Rotation;
- 旋转角度,单位为度。int Stereo3DType;
- 3D 视频的类型。参见 FFMS_Stereo3DType 枚举值。int Stereo3DFlags
- 3D 视频标志。参见 FFMS_Stereo3DFlags 枚举。double LastEndTime
- 最后一个数据包的结束时间,单位为毫秒。int HasMasteringDisplayPrimaries
- 如果非 0,则会设置以下 4 个字段。double MasteringDisplayPrimariesX[3]
- 主平面的 RGB 色彩坐标(X 轴)。double MasteringDisplayPrimariesY[3]
- 主平面的 RGB 色彩坐标(Y 轴)。double MasteringDisplayWhitePointX
- 主平面的白场坐标(X 轴)。double MasteringDisplayWhitePointY
- 主平面的白场坐标(Y 轴)。int HasMasteringDisplayLuminance
- 如果非 0,则会设置以下 2 个字段。double MasteringDisplayMinLuminance
- 主平面的最小亮度(单位 cd/m^2)。double MasteringDisplayMaxLuminance
- 主平面的最大亮度(单位 cd/m^2)。int HasContentLightLevel
- 如果非 0,则会设置以下 2 个字段。unsigned int ContentLightLevelMax
- 最大亮度(单位 cd/m^2)。unsigned int ContentLightLevelAverage
- 平均亮度(单位 cd/m^2)。
FFMS_AudioProperties
typedef struct {
int SampleFormat;
int SampleRate;
int BitsPerSample;
int Channels;
int64_t ChannelLayout;
int64_t NumSamples;
double FirstTime;
double LastTime;
double LastEndTime;
} FFMS_AudioProperties;
音频轨的基本信息(元数据)。字段说明如下:
int SampleFormat
- 表示音频的采样格式,为整数值。参阅 FFMS_SampleFormat。int SampleRate
- 音频采样率,单位为每秒的采样数。int BitsPerSample
- 采样位数(精度)。请注意,这里是指编码精度,不是数据的保存精度,并且可能会与SampleFormat
所示的精度不一致。你该明白,哪个才是有效参数吧。int Channels
- 音轨总数。int64_t ChannelLayout
- 声道的分布情况。由 FFMS_AudioChannel 定义的整数值二进制“或”组合而成,表示是否包含对应的声道数据。假设变量ChannelOrder
为声道分布值,变量FFMS_CH_EXAMPLE
为声道号,如果包含该声道数据,则(ChannelOrder & FFMS_CH_EXAMPLE)
操作的结果将为真。各声道的数据将按照 FFMS_AudioChannel 枚举定义的顺序交错排列。int64_t NumSamples
- 总数据包数。double FirstTime; double LastTime;
- 第一个包和最后一个包的时间戳,单位为毫秒。如果想知道是否存在延时,或者大致了解总的时长,本字段会有点用处。double LastEndTime
- 最后一个包的时间,单位为毫秒。
常量和预处理标志
以下常量和预处理标志比较常用,在ffms.h
中定义。
FFMS_Errors
enum FFMS_Errors {
// 没有错误
FFMS_ERROR_SUCCESS = 0,
// 大类 - 表示错误发生的时机
FFMS_ERROR_INDEX = 1, // 处理索引时
FFMS_ERROR_INDEXING, // 创建索引时
FFMS_ERROR_POSTPROCESSING, // 视频后处理时(libpostproc)
FFMS_ERROR_SCALING, // 画面缩放时(libswscale)
FFMS_ERROR_DECODING, // 音视频解码时
FFMS_ERROR_SEEKING, // 检索文件时
FFMS_ERROR_PARSER, // 解析文件时
FFMS_ERROR_TRACK, // 处理音视频轨信息时
FFMS_ERROR_WAVE_WRITER, // 写 WAVE64 文件时
FFMS_ERROR_CANCELLED, // 取消操作时
// 子类 - 表示出错原因
FFMS_ERROR_UNKNOWN = 20, // 未知错误
FFMS_ERROR_UNSUPPORTED, // 不支持的格式或操作
FFMS_ERROR_FILE_READ, // 无法读取文件
FFMS_ERROR_FILE_WRITE, // 无法写入文件
FFMS_ERROR_NO_FILE, // 文件或目录不存在
FFMS_ERROR_VERSION, // 版本错误
FFMS_ERROR_ALLOCATION_FAILED, // 内存不足
FFMS_ERROR_INVALID_ARGUMENT, // 参数非法
FFMS_ERROR_CODEC, // 解码器错误
FFMS_ERROR_NOT_AVAILABLE, // 非法操作
FFMS_ERROR_FILE_MISMATCH, // 索引与文件不匹配
FFMS_ERROR_USER // 是用户的问题
};
上述错误信息的含义,已不言自明。
FFMS_SeekMode
enum FFMS_SeekMode {
FFMS_SEEK_LINEAR_NO_RW = -1,
FFMS_SEEK_LINEAR = 0,
FFMS_SEEK_NORMAL = 1,
FFMS_SEEK_UNSAFE = 2,
FFMS_SEEK_AGGRESSIVE = 3
};
在 FFMS_CreateVideoSource 中用于控制检索模式。各值的说明如下:
FFMS_SEEK_LINEAR_NO_RW
- 不带回放的线性访问。如果后续的帧号小于等于已提交的访问请求,则会抛出异常。仅建议用于打开图片文件,对某些罕见的视频格式或许也能使用。FFMS_SEEK_LINEAR
- 线性访问。假设要访问第n
帧,则不必先对第 0 到n-1
帧进行访问。在获取第n
帧数据之前,所有从0 到n-1
帧的数据都会被解码一遍。虽然速度较慢,但可以保证某些格式的正常访问。FFMS_SEEK_NORMAL
- 安全的常规模式。根据 libavformat 返回的关键帧位置,进行检索。FFMS_SEEK_UNSAFE
- 不安全的常规模式。与FFMS_SEEK_NORMAL
相同,但在必须猜测目标位置时不会报错。FFMS_SEEK_AGGRESSIVE
- 激进模式。即使附近没有关键帧,也直接去访问。只有在做测试时,或者 libavformat 无法正确返回关键帧信息时,才会用得上。
FFMS_IndexErrorHandling
enum FFMS_IndexErrorHandling {
FFMS_IEH_ABORT = 0,
FFMS_IEH_CLEAR_TRACK = 1,
FFMS_IEH_STOP_TRACK = 2,
FFMS_IEH_IGNORE = 3
};
在建立索引的函数中用于控制解码出错后的处理方式。
FFMS_IEH_ABORT
- 取消索引并触发错误。FFMS_IEH_CLEAR_TRACK
- 清空本轨的索引数据(返回空轨)。FFMS_IEH_STOP_TRACK
- 停止索引但保留已索引数据(返回的索引中包含了至出错位置的数据)。FFMS_IEH_IGNORE
- 忽略错误,就当没发生过。
FFMS_TrackType
enum FFMS_TrackType {
FFMS_TYPE_UNKNOWN = -1,
FFMS_TYPE_VIDEO,
FFMS_TYPE_AUDIO,
FFMS_TYPE_DATA,
FFMS_TYPE_SUBTITLE,
FFMS_TYPE_ATTACHMENT
};
用于确定轨道的类型。请注意,目前所有的 API 函数,均无法处理FFMS_TYPE_VIDEO
和FFMS_TYPE_AUDIO
之外的类型。请参阅 FFMS_GetTrackType、FFMS_GetFirstTrackOfType 及其变体函数。
FFMS_SampleFormat
enum FFMS_SampleFormat {
FFMS_FMT_U8 = 0,
FFMS_FMT_S16,
FFMS_FMT_S32,
FFMS_FMT_FLT,
FFMS_FMT_DBL
};
音频采样格式。
FFMS_FMT_U8
- 每次采样一个 8 位无符号整数(uint8_t
)。FFMS_FMT_S16
- 每次采样一个 16 位带符号整数(int16_t
)。FFMS_FMT_S32
- 每次采样一个 32 位带符号整数(int32_t
)。FFMS_FMT_FLT
- 每次采样一个 32 位(单精度)浮点数(float_t
)。FFMS_FMT_DBL
- 每次采样一个 64 位(双精度)浮点数(double_t
)。
FFMS_AudioChannel
enum FFMS_AudioChannel {
FFMS_CH_FRONT_LEFT = 0x00000001,
FFMS_CH_FRONT_RIGHT = 0x00000002,
FFMS_CH_FRONT_CENTER = 0x00000004,
FFMS_CH_LOW_FREQUENCY = 0x00000008,
FFMS_CH_BACK_LEFT = 0x00000010,
FFMS_CH_BACK_RIGHT = 0x00000020,
FFMS_CH_FRONT_LEFT_OF_CENTER = 0x00000040,
FFMS_CH_FRONT_RIGHT_OF_CENTER = 0x00000080,
FFMS_CH_BACK_CENTER = 0x00000100,
FFMS_CH_SIDE_LEFT = 0x00000200,
FFMS_CH_SIDE_RIGHT = 0x00000400,
FFMS_CH_TOP_CENTER = 0x00000800,
FFMS_CH_TOP_FRONT_LEFT = 0x00001000,
FFMS_CH_TOP_FRONT_CENTER = 0x00002000,
FFMS_CH_TOP_FRONT_RIGHT = 0x00004000,
FFMS_CH_TOP_BACK_LEFT = 0x00008000,
FFMS_CH_TOP_BACK_CENTER = 0x00010000,
FFMS_CH_TOP_BACK_RIGHT = 0x00020000,
FFMS_CH_STEREO_LEFT = 0x20000000,
FFMS_CH_STEREO_RIGHT = 0x40000000
};
用于描述音轨中的声道分布情况。含义可不言自明。
你可能已经注意到了,这些常量与微软WAVEFORMATEXTENSIBLE
结构的dwChannelMask
属性定义相同。详情请参阅 相关 MSDN 文档。FFMS_CH_STEREO_LEFT
和FFMS_CH_STEREO_RIGHT
是 FFmpeg 自己扩展的,在微软的定义之外。
FFMS_Resizers
enum FFMS_Resizers {
FFMS_RESIZER_FAST_BILINEAR = 0x01,
FFMS_RESIZER_BILINEAR = 0x02,
FFMS_RESIZER_BICUBIC = 0x04,
FFMS_RESIZER_X = 0x08,
FFMS_RESIZER_POINT = 0x10,
FFMS_RESIZER_AREA = 0x20,
FFMS_RESIZER_BICUBLIN = 0x40,
FFMS_RESIZER_GAUSS = 0x80,
FFMS_RESIZER_SINC = 0x100,
FFMS_RESIZER_LANCZOS = 0x200,
FFMS_RESIZER_SPLINE = 0x400
};
在 FFMS_SetOutputFormatV2 中用于给出各种图像缩放算法。含义不言自明。
FFMS_AudioDelayModes
enum FFMS_AudioDelayModes {
FFMS_DELAY_NO_SHIFT = -3,
FFMS_DELAY_TIME_ZERO = -2,
FFMS_DELAY_FIRST_VIDEO_TRACK = -1
};
描述对音频延时的处理方式。详细解释请参阅 FFMS_CreateAudioSource。
FFMS_ChromaLocations
typedef enum FFMS_ChromaLocations {
FFMS_LOC_UNSPECIFIED = 0,
FFMS_LOC_LEFT = 1,
FFMS_LOC_CENTER = 2,
FFMS_LOC_TOPLEFT = 3,
FFMS_LOC_TOP = 4,
FFMS_LOC_BOTTOMLEFT = 5,
FFMS_LOC_BOTTOM = 6
} FFMS_ChromaLocations;
表示色度采样点在帧画面内的位置。
FFMS_ColorRanges
enum FFMS_ColorRanges {
FFMS_CR_UNSPECIFIED = 0,
FFMS_CR_MPEG = 1,
FFMS_CR_JPEG = 2,
};
用于描述 YUV 流中合法的亮度范围。FFMS_CR_MPEG
是标准的“TV 范围”,带有上下裕量(headroom、footroom)。也就是说,合法的亮度值范围是从 16 到 235,带有 8 位色彩值。FFMS_CR_JPEG
是全范围的,所有亮度值均可用。
FFMS_Stereo3DType
typedef enum FFMS_Stereo3DType {
FFMS_S3D_TYPE_2D = 0,
FFMS_S3D_TYPE_SIDEBYSIDE,
FFMS_S3D_TYPE_TOPBOTTOM,
FFMS_S3D_TYPE_FRAMESEQUENCE,
FFMS_S3D_TYPE_CHECKERBOARD,
FFMS_S3D_TYPE_SIDEBYSIDE_QUINCUNX,
FFMS_S3D_TYPE_LINES,
FFMS_S3D_TYPE_COLUMNS
} FFMS_Stereo3DType;
用于表示 3D 视频的类型。
FFMS_Stereo3DFlags
typedef enum FFMS_Stereo3DFlags {
FFMS_S3D_FLAGS_INVERT = 1
} FFMS_Stereo3DFlags;
3D 视频的标志。
FFMS_CC
#ifdef _WIN32
# define FFMS_CC __stdcall
#else
# define FFMS_CC
#endif
本宏是为了方便 FFMS2 API 函数的调用和回调。如果定义了 _WIN32 则为 __stdcall,否则就未用上。
图像类型
FFMS_Frame->PictType
中存放的值:
I: 关键帧(Intra)
P: 差别帧(Predicted)
B: 双向差别帧(Bi-dir predicted)
S: S(GMC)-VOP MPEG4
i: 切换关键帧(Switching Intra)
p: 切换差别帧(Switching Predicted)
b: FF_BI_TYPE(无意义帧)
?: 未能识别
命名音频文件用到的格式串
可以用以下变量:
%sourcefile%
- 与源文件名相同,也就是要解码的文件名。%trackn%
- 轨号。%trackzn%
- 以 0 补足 2 位的轨号。%samplerate%
- 音频采样率。%channels%
- 声道号。%bps%
- 采样位数。%delay%
- 延时。确切地说,是第一个音频数据包的时间戳。
示例:%sourcefile%_track%trackzn%.w64