# 基础开发

FFmpeg 是一款知名的开源音视频处理软件,它提供了丰富而友好的接口支持开发者进行二次开发。

# 代码结构

目录 说明
libavcodec 提供了一系列编码器的实现
libavformat 实现在流协议,容器格式及其基本 IO 访问
libavutil 包括了 Hash 器,解码器和各种工具函数
libavfilter 提供了各种音视频过滤器
libavdevice 提供了访问捕获设备和回放设备的接口
libswresample 实现了混音和重采样
libswscale 实现了色彩转换和缩放功能

# 日志系统

通过三步就能输出日志:

  • 引入头文件: include <libavutil/log.h>
  • 设置日志级别: av_log_set_level(AV_LOG_DEBUG)
  • 打印日志: av_log(NULL, AV_LOG_INFO, " ...%s\n", op)

常用的日志级别:

  • AV_LOG_ERROR
  • AV_LOG_WARNING
  • AV_LOG_DEBUG
  • AV_LOG_INFO
#include <libavutil/log.h>

int main(int argc, char* argv[])
{
  av_log_set_level(AV_LOG_DEBUG);
  av_log(NULL, AV_LOG_DEBUG, "hello world");

  return 0;
}

# 文件操作

删除文件:

#include <libavformat/avformat.h>

int main(int argc, char* argv[])
{
  int ret;

  ret = avpriv_io_delete("./test.txt");

  if (ret < 0) {
    av_log(NULL, AV_LOG_ERROR, "Delete failed");

    return -1;
  }

  return 0;
}

移动文件则可以 avpriv_io_move 函数。

# 目录操作

和文件操作比较类似,操作目录需要先打开目录,然后读取目录中的每一项(AVIODirEntry)进行操作,最后使用完之后要进行关闭,整个过程通过 AVIODirContext 串联起来。

#include <libavutil/avutil.h>
#include <libavformat/avformat.h>

int main(int argc, char *argv[])
{
  int ret;
  AVIODirContext *ctx = NULL;
  AVIODirEntry *entry = NULL;

  av_log_set_level(AV_LOG_INFO);
  ret = avio_open_dir(&ctx, "./", NULL); // 打开

  if (ret < 0)
  {
    av_log(NULL, AV_LOG_ERROR, "Can not open dir: %s\n", av_err2str(ret));
  }

  while (1)
  {
    ret = avio_read_dir(ctx, &entry); // 读取

    if (ret < 0)
    {
      av_log(NULL, AV_LOG_ERROR, "Can not open dir: %s\n", av_err2str(ret));

      goto __fail;
    }

    if (!entry)
    {
      break;
    }

    av_log(NULL, AV_LOG_INFO, "%12" PRId64 " %s \n", entry->size, entry->name);
    avio_free_directory_entry(&entry);
  }

__fail:
  avio_close_dir(&ctx); // 关闭

  return 0;
}

# 多媒体文件信息

多媒体文件其实是个容器,在容器里有许多的流(Stream/Track),从流中读取的数据成为包,在一个包中包含着一个或多个帧。

所以 FFmpeg 在操作数据时会首先对多媒体文件进行解复用拿到流,然后读取其中的数据包,对数据包解码后就可以进行各种操作,最后释放相关的资源。

在整个过程中我们需要使用到 AVFormatContext 来串联整个过程,期间可以使用 AVStream 来读取其中的流,然后截取流得到一个个包,也就是 AVPacket。

接下来我们尝试打印音视频信息,其中涉及到以下的几个函数:

  • av_register_all(): 注册所有的编解码器、复用/解复用组件等
  • avformat_open_input()/avformat_close_input(): 打开/关闭多媒体数据并且获得一些相关的信息
  • av_dump_format(): 打印关于输入或输出格式的详细信息
#include <libavutil/log.h>
#include <libavformat/avformat.h>

int main(int argc, char *argv[])
{
  int ret;
  AVFormatContext *fmt_ctx = NULL;

  av_log_set_level(AV_LOG_INFO);
  // av_register_all(); // 新版中已经不需要

  // 打开多媒体的第三个参数为媒体文件格式,默认根据扩展名决定,最后一个参数为额外的配置信息
  ret = avformat_open_input(&fmt_ctx, "./input.mp4", NULL, NULL);

  if (ret < 0)
  {
    av_log(NULL, AV_LOG_ERROR, "Can not open file: %s\n", av_err2str(ret));

    return -1;
  }

  // 此处的第二个参数为流的索引,第四个参数为 0 表示上下文是输入(将打印输入流),为 1 则表示输出(将打印输出流)
  av_dump_format(fmt_ctx, 0, "./input.mp4", 0);
  avformat_close_input(&fmt_ctx);

  return 0;
}