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 依赖于以下库:

  • FFmpeg

    • 建议的编译参数:--disable-debug --disable-muxers --disable-encoders --disable-filters --disable-hwaccels --disable-network --disable-devices --enable-runtime-cpudetect(如果你是在编译正式发布库,那么最好是开启 runtime-cpudetect;如果不关闭 disable-debug,dll 的尺寸将增大很多)。
  • zlib

非 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_GetNumTracksIFFMS_GetTrackTypeIFFMS_GetCodecNameI 函数,可以从 indexer 对象中可以查到一些信息,以便获悉文件中的轨道(track)数量及其类型。通过调用 FFMS_TrackIndexSettingsFFMS_TrackTypeIndexSettings、[FFMS_SetAudioNameCallback][SetAudioNameCallback] 和 FFMS_SetProgressCallback,可以对索引器进行一些配置,比如对哪些轨道需要建立索引。然后就可以调用 FFMS_DoIndexing2 建立索引了。如果想要中止建立索引的过程,可以调用 FFMS_CancelIndexing 函数。FFMS_DoIndexing2FFMS_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_GetNumTracksFFMS_GetTrackTypeFFMS_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_VideoSourceFFMS_AudioSource对象,释放由 FFMS_CreateVideoSourceFFMS_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_GetFrameFFMS_GetFrameByTime 的调用结果都会收到影响,直至下一次 FFMS_SetOutputFormatV2FFMS_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_SetInputFormatVFFMS_ResetInputFormatV 之前,FFMS_GetFrameFFMS_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_GetPixFmtFFMS_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_CreateVideoSourceFFMS_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_CreateVideoSourceFFMS_CreateAudioSource打开某个轨道时,即可使用本函数。如果已经用FFMS_CreateVideoSourceFFMS_CreateAudioSource打开过了该轨道,那么更可靠的方式是用FFMS_GetTrackFromVideoFFMS_GetTrackFromAudio。请注意,如果给出非法或不存在的轨道编号,将会导致不可预料的后果,一般是会报内存访问冲突(access violation)的错误。还请注意一点,返回的FFMS_Track仅在其所属的FFMS_Index生命周期内才有效。

参数

FFMS_Index *Index

指向FFMS_Index对象的指针,其中包含了必要的轨道信息。

int Track

轨道编号,对应的解封器也会认到相同的编号(参阅 FFMS_GetNumTracksFFMS_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_VideoSourceFFMS_AudioSource对象获取轨道的基本信息,返回FFMS_Track对象指针。一般情况下,这两个函数要比 FFMS_GetTrackFromIndex 更为可靠。因为在给出了不存在的轨道编号时,本函数不会引发访问冲突错误,而是返回不包含索引信息的FFMS_Track。如果索引对象已被销毁,本函数将返回失效的对象。请注意,返回的FFMS_Track对象仅在其所属的FFMS_VideoSourceFFMS_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_TrackIndexSettingsFFMS_TrackTypeIndexSettingsFFMS_SetAudioNameCallbackSetAudioNameCallbackFFMS_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 Currentint64_t Total - 索引的进度指示(已完成帧数/总帧数)。
  • void *Private - 与传给FFMS_SetProgressCallbackPrivate参数为同一个指针,用途由你决定。比如在图形用户界面程序中,可用于传入进度条对象,以便在调用索引函数时更新进度。

回调函数返回 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 EncodedWidthint EncodedHeight - 原始分辨率(单位为像素),也即压缩文件里保存的未经缩放的分辨率。请注意,一个数据流不一定所有帧都是相同的分辨率。
  • int EncodedPixelFormat - 原始像素格式,即压缩文件里保存的编码格式。
  • int ScaledWidthint ScaledHeight - 输出分辨率(单位为像素),即Data字段内图像数据的实际分辨率。如果未经缩放则设为 -1。
  • int ConvertedPixelFormat - 输出像素格式,即Data字段内图像数据的实际格式。- int KeyFrame - 如果本帧是关键帧,则为非 0。否则为零。
  • int RepeatPict - RFF 参数,也即显示时间应为1+RepeatPict个时基单位。这里的时基单位是 RFF 专用的,在FFMS_VideoProperties->RFFDenominatorFFMS_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_VIDEOFFMS_TYPE_AUDIO之外的类型。请参阅 FFMS_GetTrackTypeFFMS_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_LEFTFFMS_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

FFMS2 API 译文 [原创]的更多相关文章

  1. FFMS2 官方说明译文 [原创]

    原文:https://github.com/FFMS/ffms2 译文:http://www.cnblogs.com/popapa/p/ffms2.html 采集日期:2018-3-18 FFmpeg ...

  2. 【最后一篇API译文】Android开发-API指南- Contacts Provider

    Contacts Provider 今年加入了某字幕组,加之杂事颇多,许久未添新文了,惭愧之极. 在听闻 Google 即将重返中国后,近日忽又发现官方网站正在放出 API 中文版,比如本文.当然不是 ...

  3. TimelineJS JSON 数据格式 - 译文 [原创]

    TimelineJS 是用于绘制时间轴的 Javascript 开源脚本,目前是 TimelineJS3 版.参阅 https://github.com/NUKnightLab/TimelineJS3 ...

  4. 10分钟了解 pandas - pandas官方文档译文 [原创]

    10 Minutes to pandas 英文原文:https://pandas.pydata.org/pandas-docs/stable/10min.html 版本:pandas 0.23.4 采 ...

  5. OWASP 关于会话管理 - 译文 [原创]

    英文原文:https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Session_Management_Cheat_Shee ...

  6. 设备树驱动API【原创】

    #include <linux/init.h> #include <linux/module.h> #include <linux/of.h> #include & ...

  7. Daphile 安装手册 -- 官方文档译文 [原创]

    Daphile 安装手册(Daphile Installation) 英文原文:https://www.daphile.com/download/DaphileInstallation.pdf 采集日 ...

  8. Daphile FAQ -- 官方文档译文 [原创]

    Daphile FAQ 英文原文:https://www.daphile.com/download/FAQ.txt 采集日期:2021-01-03 常见问题解答:(FAQ) Q1:没有声音.Daphi ...

  9. Python 并行计算那点事 -- 译文 [原创]

    Python 并行计算的那点事1(The Python Concurrency Story) 英文原文:https://powerfulpython.com/blog/python-concurren ...

随机推荐

  1. BZOJ 1877 晨跑 拆点费用流

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1877 题目大意: Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧 ...

  2. jar的解压与打包

    当我们在公司上班时候,时长需要将本地开发的作业打包上传到集群运行,由于项目过多依赖会导致jar比较庞大,因此每一次上传都比较浪费时间,为了节省时间可以使用两种办法: 1:将所有依赖一次性上传到集群上, ...

  3. etcd 删除

    vim /etc/sysconfig/flanneld FLANNEL_ETCD_ENDPOINTS="https://192.168.30.241:2379,https://192.168 ...

  4. Linux Shell常用技巧(五)

    十一.  awk编程:    1.  变量:    在awk中变量无须定义即可使用,变量在赋值时即已经完成了定义.变量的类型可以是数字.字符串.根据使用的不同,未初始化变量的值为0或空白字符串&quo ...

  5. js call().apply().bind()的用法

    function Person(age) { this.age = age; } Person.prototype.sayHi = function (x, y) { console.log((x + ...

  6. MySQL 性能测试

    MySQL 查询优化器有几个目标,但是其中最主要的目标是尽可能地使用索引,并且使用最严格的索引来消除尽可能多的数据行.最终目标是提交 SELECT 语句查找数据行,而不是排除数据行.优化器试图排除数据 ...

  7. React实战一

    目录 1. 搭建环境 2. React知识点 1. 组件 1.1 定义一个组件 1.2 组合与拆分组件 1.3 组件传值 1.4 state 1.5 生命周期函数 1.6 无状态组件 1.7 List ...

  8. zookeeper入门实例

    package org.merit.test.zookeepertest; import java.io.IOException;import java.util.List;import java.u ...

  9. [agc008E]Next or Nextnext-[dp+思考题]

    Description 传送门 Solution 官方题解 然后我谈下个人理解.由于我们的两个条件只要任意满足,则在p的图中i有两种连边法:i->p[i],i->p[p[i]]. 我们考虑 ...

  10. 07 -模型层ORM

    1.orm简介 2. models.py from django.db import models # Create your models here. class Book(models.Model ...