📜  使用 ffmpeg 将视频转换为 gif - C 编程语言(1)

📅  最后修改于: 2023-12-03 14:49:39.367000             🧑  作者: Mango

使用 ffmpeg 将视频转换为 gif - C 编程语言

简介

FFmpeg 是一个开源的高性能跨平台视频处理库,它支持多种视频格式的编解码、转换、输出等操作,为开发者提供了强大且灵活的视频处理能力。本文介绍如何使用 FFmpeg 在 C 语言程序中将视频转换为 gif 动画。

前置条件

在开始本教程之前,需要先安装 FFmpeg 库和相关依赖。可以参考以下链接进行安装:

准备工作

在 C 语言程序中使用 FFmpeg 需要引入相关头文件和库文件,并进行初始化操作。以下是准备工作的代码。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/mathematics.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>

int main(int argc, char *argv[]) {
  AVFormatContext *format_ctx = NULL; // AVFormatContext 结构体用于封装输入文件信息
  AVCodecContext *codec_ctx = NULL;   // AVCodecContext 结构体用于封装编码器信息
  AVCodec *codec = NULL;             // AVCodec 结构体用于描述编解码器
  AVPacket pkt;                       // AVPacket 数据结构用于存储压缩的视频帧
  AVFrame *frame = NULL;              // AVFrame 结构体用于存储解码后的视频帧
  int stream_idx = -1;                // 视频流索引
  int ret = 0;                        // 函数调用返回值
  int got_frame = 0;                  // 解码器是否成功读取到一帧视频帧

  // 初始化 FFmpeg 库
  av_register_all();

  // 打开视频文件并读取格式信息
  ret = avformat_open_input(&format_ctx, argv[1], NULL, NULL);
  if (ret != 0) {
    fprintf(stderr, "Unable to open input file: %s\n", argv[1]);
    return -1;
  }

  // 查找视频流信息
  ret = avformat_find_stream_info(format_ctx, NULL);
  if (ret < 0) {
    fprintf(stderr, "Unable to find video stream in the input file\n");
    return -1;
  }

  // 查找视频编解码器
  codec = avcodec_find_decoder(format_ctx->streams[stream_idx]->codecpar->codec_id);
  if (!codec) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1;
  }

  // 初始化编解码器上下文
  codec_ctx = avcodec_alloc_context3(codec);
  if (!codec_ctx) {
    fprintf(stderr, "Unable to allocate codec context\n");
    return -1;
  }

  // 将视频流参数拷贝到编解码器上下文中
  avcodec_parameters_to_context(codec_ctx, format_ctx->streams[stream_idx]->codecpar);

  // 打开编解码器
  if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
    fprintf(stderr, "Unable to open codec\n");
    return -1;
  }

  // 分配解码后视频帧内存
  frame = av_frame_alloc();
  if (!frame) {
    fprintf(stderr, "Unable to allocate video frame\n");
    return -1;
  }

  // 遍历视频流信息查找视频流索引
  for (int i = 0; i < format_ctx->nb_streams; i++) {
    if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
      stream_idx = i;
      break;
    }
  }

  // 判断是否找到视频流
  if (stream_idx == -1) {
    fprintf(stderr, "Unable to find video stream in the input file\n");
    return -1;
  }

  // 遍历视频流中的视频帧并逐帧转换为 gif 图像
  while (av_read_frame(format_ctx, &pkt) >= 0) {
    if (pkt.stream_index == stream_idx) {
      avcodec_decode_video2(codec_ctx, frame, &got_frame, &pkt);
      if (got_frame) {
        // 将解码后的视频帧格式转换为 RGB24 格式
        AVFrame *rgb_frame = av_frame_alloc();
        rgb_frame->format = AV_PIX_FMT_RGB24;
        rgb_frame->width = frame->width;
        rgb_frame->height = frame->height;
        av_frame_get_buffer(rgb_frame, 32);

        struct SwsContext *sws_ctx = sws_getContext(frame->width, frame->height, codec_ctx->pix_fmt, 
          frame->width, frame->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL);

        sws_scale(sws_ctx, frame->data, frame->linesize, 0, frame->height, rgb_frame->data, 
          rgb_frame->linesize);

        // 将 RGB24 格式的视频帧转换为 gif 图像并保存到磁盘
        // ...

        av_frame_free(&rgb_frame);
      }
    }

    av_packet_unref(&pkt);
  }

  // 释放内存和资源
  av_frame_free(&frame);
  avcodec_free_context(&codec_ctx);
  avformat_close_input(&format_ctx);
  avformat_free_context(format_ctx);

  return 0;
}
视频帧转 gif 图像

在遍历视频流信息并逐帧解码出视频帧之后,我们需要将解码出来的视频帧转换为 gif 图像并保存到磁盘中。下面的代码片段演示了如何使用 gif.h 库将 RGB24 格式的视频帧转换为 gif 图像。

#include "gif.h"

// 将 RGB24 格式的视频帧转换为 gif 图像
    GifWriter gif_writer;
    if (frame_count == 0) {
      GifBegin(&gif_writer, output_path, frame->width, frame->height, 2);
    } else {
      GifWriteFrame(&gif_writer, rgb_frame->data[0], frame->width, frame->height, 2);
    }

    frame_count++;

    if (frame_count == 100) {
      GifEnd(&gif_writer);
      break;
    }
结语

本文介绍了如何在 C 语言程序中使用 FFmpeg 库将视频转换为 gif 动画。虽然需要引入许多头文件以及完成初始化、解码、转换等步骤,但是拥有了本文所讲述的基础知识后,开发者们即可掌握 FFmpeg 库的强大功能。