21xrx.com
2025-06-15 04:17:32 Sunday
登录
文章检索 我的文章 写文章
使用C++编写FFmpeg进行截图保存
2023-10-25 22:36:23 深夜i     47     0
C++ FFmpeg 编写 截图 保存

FFmpeg是一种广泛使用的开源多媒体框架,它提供了丰富的工具和库,可用于处理视频、音频和多媒体流。在本文中,我们将学习如何使用C++编写FFmpeg来实现截图保存功能。

首先,我们需要安装FFmpeg并将其添加到系统环境变量中。Windows用户可以从FFmpeg官方网站下载预编译的二进制文件,并将其添加到系统路径中。Linux用户可以使用包管理器安装FFmpeg。

接下来,我们将创建一个C++项目,并在项目中添加FFmpeg的头文件和库文件的引用。为此,我们需在项目设置中指明FFmpeg的依赖项路径,并在代码中使用#include来引用相关的头文件。

编写截图功能的关键代码如下所示:

#include <iostream>
extern "C"
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
int main() {
  av_register_all();
  AVFormatContext* pFormatCtx = nullptr;
  AVCodecContext* pCodecCtx = nullptr;
  AVCodec* pCodec = nullptr;
  AVPacket packet;
  AVFrame* pFrame = nullptr;
  AVFrame* pFrameRGB = nullptr;
  int frameFinished;
  int numBytes;
  uint8_t* buffer = nullptr;
  int videoStream;
  const char* filename = "input.mp4";
  const char* saveFilename = "screenshot.jpg";
  int targetFrame = 100;
  int width = 640;
  int height = 480;
  // 打开视频文件
  if (avformat_open_input(&pFormatCtx, filename, nullptr, nullptr) != 0)
    std::cout << "无法打开视频文件" << std::endl;
    return -1;
  
  // 检索视频流信息
  if (avformat_find_stream_info(pFormatCtx, nullptr) < 0)
    std::cout << "无法检索到视频流信息" << std::endl;
    return -1;
  
  
  // 查找视频流索引
  videoStream = -1;
  for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
    if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
      videoStream = i;
      break;
    
  }
  
  if (videoStream == -1)
    std::cout << "无法找到视频流" << std::endl;
    return -1;
  
  
  // 获取编解码器上下文
  pCodecCtx = pFormatCtx->streams[videoStream]->codec;
  
  // 查找解码器
  pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
  
  if (pCodec == nullptr)
    std::cout << "无法找到解码器" << std::endl;
    return -1;
  
  
  // 打开解码器
  if (avcodec_open2(pCodecCtx, pCodec, nullptr) < 0)
    std::cout << "无法打开解码器" << std::endl;
    return -1;
  
  
  // 创建一个帧信息对象
  pFrame = av_frame_alloc();
  if (pFrame == nullptr)
    std::cout << "无法分配帧内存" << std::endl;
    return -1;
  
  
  // 创建一个RGB帧信息对象
  pFrameRGB = av_frame_alloc();
  if (pFrameRGB == nullptr)
    std::cout << "无法分配RGB帧内存" << std::endl;
    return -1;
  
  
  // 计算帧大小
  numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, width, height);
  
  // 在内存中创建帧数据缓冲区
  buffer = reinterpret_cast<uint8_t*> (av_malloc(numBytes * sizeof(uint8_t)));
  
  // 为帧对象分配缓冲区
  avpicture_fill(reinterpret_cast<AVPicture*> (pFrameRGB), buffer, AV_PIX_FMT_RGB24, width, height);
  
  int currentFrame = 0;
  while (av_read_frame(pFormatCtx, &packet) >= 0) {
    if (packet.stream_index == videoStream) {
      // 解码视频帧
      avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
      
      // 只处理目标帧
      if (++currentFrame == targetFrame) {
        // 图像转换
        SwsContext* swsCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
                          width, height, AV_PIX_FMT_RGB24,
                          SWS_BILINEAR, nullptr, nullptr, nullptr);
        
        sws_scale(swsCtx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
        
        // 保存截图
        FILE* file = fopen(saveFilename, "wb");
        if (file != nullptr) {
          fwrite(pFrameRGB->data[0], 1, numBytes, file);
          fclose(file);
          std::cout << "成功保存截图" << std::endl;
        } else
          std::cout << "无法打开截图文件" << std::endl;
        
        
        sws_freeContext(swsCtx);
      }
    }
  
    av_free_packet(&packet);
  }
  
  av_free(pFrame);
  av_free(pFrameRGB);
  avcodec_close(pCodecCtx);
  avformat_close_input(&pFormatCtx);
  
  avformat_network_deinit();
  
  return 0;
}

在上述代码中,我们首先调用`av_register_all()`来初始化FFmpeg库。然后,我们打开视频文件,检索视频流信息,并查找视频流索引。接下来,我们获取编解码器上下文,并查找解码器。然后,我们打开解码器,并创建一个帧信息对象和一个RGB帧信息对象。在循环中,我们读取每一帧,并选择目标帧进行解码和图像转换,最后将截图保存到文件中。

完成了以上步骤后,我们可以使用C++编译器来编译并运行我们的代码。如果一切正常,程序将成功截取指定目标帧并保存为JPEG图像。

总结而言,使用C++编写FFmpeg进行截图保存功能可以实现简单而高效的多媒体处理。掌握这项技术将为开发各种多媒体应用程序提供很大的便利和灵活性。为了进一步提升应用程序的功能和性能,我们可以探索更多FFmpeg的特性和用法。

  
  

评论区