FFMS2 API 译文 [原创]

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

posted on 2018-03-19 12:52  呆呆大虾  阅读(1281)  评论(0编辑  收藏  举报

导航