ZBLOG

C++ FFMPEG 解码MP4得到的每一帧图片数据,使用opencv将图片数据转成1920*1080的BGR

要使用C++和FFmpeg解码MP4文件并将每一帧转换为1920x1080的BGR格式的图像数据,你可以按照以下步骤进行:

  1. 安装FFmpeg:确保你已经安装了FFmpeg库,并在你的C++项目中配置好了相应的头文件和库。

  2. 安装OpenCV:同样需要确保OpenCV已安装,并正确设置了相应的环境。

  3. 编写代码:下面是一个简单的示例代码,演示如何使用FFmpeg解码MP4文件,并使用OpenCV将每一帧转换为1920x1080的BGR图像。

#include <iostream>
#include <opencv2/opencv.hpp>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}

void decodeVideo(const char* filename) {
    av_register_all();

    AVFormatContext* formatCtx = nullptr;
    if (avformat_open_input(&formatCtx, filename, nullptr, nullptr) != 0) {
        std::cerr << "Could not open the file." << std::endl;
        return;
    }

    if (avformat_find_stream_info(formatCtx, nullptr) < 0) {
        std::cerr << "Could not find stream info." << std::endl;
        return;
    }

    int videoStreamIndex = -1;
    for (unsigned int i = 0; i < formatCtx->nb_streams; i++) {
        if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIndex = i;
            break;
        }
    }

    if (videoStreamIndex == -1) {
        std::cerr << "No video stream found." << std::endl;
        return;
    }

    AVCodecParameters* codecParams = formatCtx->streams[videoStreamIndex]->codecpar;
    AVCodec* codec = avcodec_find_decoder(codecParams->codec_id);
    
    if (!codec) {
        std::cerr << "Unsupported codec!" << std::endl;
        return;
    }

    AVCodecContext* codecCtx = avcodec_alloc_context3(codec);
    
    if (avcodec_parameters_to_context(codecCtx, codecParams) < 0) {
        std::cerr << "Failed to copy codec parameters." << std::endl;
        return;
    }

    if (avcodec_open2(codecCtx, codec, nullptr) < 0) {
        std::cerr << "Could not open codec." << std::endl;
        return;
    }

    AVFrame* frame = av_frame_alloc();
    
   // Allocate an RGB image buffer
   uint8_t* buffer = (uint8_t*) av_malloc(av_image_get_buffer_size(AV_PIX_FMT_BGR24, 1920, 1080, 1));
   AVFrame* rgbFrame = av_frame_alloc();
   av_image_fill_arrays(rgbFrame->data, rgbFrame->linesize, buffer, AV_PIX_FMT_BGR24, 1920, 1080, 1);

   struct SwsContext* sws_ctx = sws_getContext(codecCtx->width,
                                                  codecCtx->height,
                                                  codecCtx->pix_fmt,
                                                  1920,
                                                  1080,
                                                  AV_PIX_FMT_BGR24,
                                                  SWS_BILINEAR,
                                                  nullptr,
                                                  nullptr,
                                                  nullptr);

   AVPacket packet;

   while (av_read_frame(formatCtx, &packet) >= 0) {
       if (packet.stream_index == videoStreamIndex) {
           int response = avcodec_send_packet(codecCtx, &packet);
           while (response >= 0) {
               response = avcodec_receive_frame(codecCtx, frame);
               if (response == AVERROR(EAGAIN) || response == AVERROR_EOF)
                   break;

               // Convert the frame to BGR
               sws_scale(sws_ctx,
                         frame->data,
                         frame->linesize,
                         0,
                         codecCtx->height,
                         rgbFrame->data,
                         rgbFrame->linesize);

               // Use OpenCV to display/save the image
               cv::Mat img(1080, 1920, CV_8UC3, rgbFrame->data[0]);
               cv::imshow("Frame", img);
               cv::waitKey(30); // Adjust delay as necessary
           }
       }
       av_packet_unref(&packet);
   }

   // Clean up
   sws_freeContext(sws_ctx);
   av_free(buffer);
   av_frame_free(&rgbFrame);
   av_frame_free(&frame);
   avcodec_free_context(&codecCtx);
   avformat_close_input(&formatCtx);
}

int main(int argc, char** argv){
     if(argc <2){
         std::cout<<"Usage: "<<argv[0]<<" <video_file>"<<std::endl; 
         return-1; 
     } 
     
     decodeVideo(argv[1]); 
     return 0; 
}

注意事项:

  • 请根据实际情况修改 filename 的路径。
  • 确保在链接时包含必要的 FFmpeg 和 OpenCV 库。
  • 根据输入视频分辨率适当调整目标分辨率(此处设定为1920x1080)。
  • 在显示或保存帧时,确保根据需求调整延迟或添加其他处理逻辑。

以上是一个基本框架,可以根据你的需求进一步扩展和优化。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://sdn.0voice.com/?id=7705

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?