OpenCV|FFmpeg – OpenCV cv::Mat与FFmpeg AVFrame的相互转换
本文作者:StubbornHuang
版权声明:本文为站长原创文章,如果转载请注明原文链接!
原文标题:OpenCV|FFmpeg – OpenCV cv::Mat与FFmpeg AVFrame的相互转换
原文链接:https://www.stubbornhuang.com/2133/
发布于:2022年05月20日 10:50:21
修改于:2022年05月20日 15:50:04

1 OpenCV cv::Mat与FFmpeg AVFrame相互转换
最近在处理OpenCV采集摄像头图片然后使用ffmpeg编码为h264裸流,之后再将h264裸流转换为OpenCV cv::Mat进行显示的问题,在这个过程中,如何将OpenCV的cv::Mat转化为FFmpeg AVFrame在进行h264编码,以及如何将h264解码后的AVFrame转换为cv::Mat是两个核心的问题,下文将简单展示OpenCV cv::Mat与FFmpeg AVFrame相互转换的核心代码,主要使用了FFmpeg中主要用于视频像素格式转换和视频缩放的sws_getContext和sws_scale函数。
注意这里使用的ffmpeg的版本为4.1,使用更低版本注意API适配,使用更高版本注意丢弃API的更换。
1.1 OpenCV cv::Mat转换为FFmpeg AVFrame
void CvMatToAVFrame(const cv::Mat& input_mat, AVFrame* out_avframe)
{
int image_width = input_mat.cols;
int image_height = input_mat.rows;
int cvLinesizes[1];
cvLinesizes[0] = input_mat.step1();
SwsContext* openCVBGRToAVFrameSwsContext = sws_getContext(
image_width,
image_height,
AVPixelFormat::AV_PIX_FMT_BGR24,
image_width,
image_height,
AVPixelFormat::AV_PIX_FMT_YUV420P,
SWS_FAST_BILINEAR,
nullptr, nullptr, nullptr
);
sws_scale(openCVBGRToAVFrameSwsContext,
&input_mat.data,
cvLinesizes,
0,
image_height,
out_avframe->data,
out_avframe->linesize);
if (openCVBGRToAVFrameSwsContext != nullptr)
{
sws_freeContext(openCVBGRToAVFrameSwsContext);
openCVBGRToAVFrameSwsContext = nullptr;
}
}
1.2 FFmpeg AVFrame转换为OpenCV cv::Mat
cv::Mat AVFrameToCvMat(AVFrame* input_avframe)
{
int image_width = input_avframe->width;
int image_height = input_avframe->height;
cv::Mat resMat(image_height, image_width, CV_8UC3);
int cvLinesizes[1];
cvLinesizes[0] = resMat.step1();
SwsContext* avFrameToOpenCVBGRSwsContext = sws_getContext(
image_width,
image_height,
AVPixelFormat::AV_PIX_FMT_YUV420P,
image_width,
image_height,
AVPixelFormat::AV_PIX_FMT_BGR24,
SWS_FAST_BILINEAR,
nullptr, nullptr, nullptr
);
sws_scale(avFrameToOpenCVBGRSwsContext,
input_avframe->data,
input_avframe->linesize,
0,
image_height,
&resMat.data,
cvLinesizes);
if (avFrameToOpenCVBGRSwsContext != nullptr)
{
sws_freeContext(avFrameToOpenCVBGRSwsContext);
avFrameToOpenCVBGRSwsContext = nullptr;
}
return resMat;
}
1.3 使用示例
#include <iostream>
// ffmpeg
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"
#include "libswscale/swscale.h"
#include <libavutil/imgutils.h>
}
// opencv
#include "opencv/cv.h"
#include "opencv2/opencv.hpp"
void CvMatToAVFrame(const cv::Mat& input_mat, AVFrame* out_avframe)
{
int image_width = input_mat.cols;
int image_height = input_mat.rows;
int cvLinesizes[1];
cvLinesizes[0] = input_mat.step1();
SwsContext* openCVBGRToAVFrameSwsContext = sws_getContext(
image_width,
image_height,
AVPixelFormat::AV_PIX_FMT_BGR24,
image_width,
image_height,
AVPixelFormat::AV_PIX_FMT_YUV420P,
SWS_FAST_BILINEAR,
nullptr, nullptr, nullptr
);
sws_scale(openCVBGRToAVFrameSwsContext,
&input_mat.data,
cvLinesizes,
0,
image_height,
out_avframe->data,
out_avframe->linesize);
if (openCVBGRToAVFrameSwsContext != nullptr)
{
sws_freeContext(openCVBGRToAVFrameSwsContext);
openCVBGRToAVFrameSwsContext = nullptr;
}
}
cv::Mat AVFrameToCvMat(AVFrame* input_avframe)
{
int image_width = input_avframe->width;
int image_height = input_avframe->height;
cv::Mat resMat(image_height, image_width, CV_8UC3);
int cvLinesizes[1];
cvLinesizes[0] = resMat.step1();
SwsContext* avFrameToOpenCVBGRSwsContext = sws_getContext(
image_width,
image_height,
AVPixelFormat::AV_PIX_FMT_YUV420P,
image_width,
image_height,
AVPixelFormat::AV_PIX_FMT_BGR24,
SWS_FAST_BILINEAR,
nullptr, nullptr, nullptr
);
sws_scale(avFrameToOpenCVBGRSwsContext,
input_avframe->data,
input_avframe->linesize,
0,
image_height,
&resMat.data,
cvLinesizes);
if (avFrameToOpenCVBGRSwsContext != nullptr)
{
sws_freeContext(avFrameToOpenCVBGRSwsContext);
avFrameToOpenCVBGRSwsContext = nullptr;
}
return resMat;
}
int main()
{
cv::Mat input_image = cv::imread("C:/Users/Administrator/Desktop/example.jpg");
AVFrame* avFrame = av_frame_alloc();
avFrame->format = AVPixelFormat::AV_PIX_FMT_YUV420P;
avFrame->width = input_image.cols;
avFrame->height = input_image.rows;
// 为需要创建的YUV Frame分配内存
if (av_frame_get_buffer(avFrame, 0) < 0)
{
av_frame_free(&avFrame);
avFrame = nullptr;
return -1;
}
cv::imshow("解码前", input_image);
// OpenCV cv::Mat转换成AVFrame
CvMatToAVFrame(input_image,avFrame);
// 将AVFrame转换成OpenCV cv::Mat
cv::Mat out_avFrameToMat = AVFrameToCvMat(avFrame);
cv::imshow("解码后", out_avFrameToMat);
cv::waitKey(0);
cv::destroyAllWindows();
// free memory
if (avFrame != nullptr)
{
av_frame_free(&avFrame);
avFrame = nullptr;
}
return 0;
}
从示例程序的结果上看,上述的转换代码是正确的

当前分类随机文章推荐
- C++ - 使用ffmpeg读取视频旋转角度并使用OpenCV根据旋转角度对视频进行旋转复原 阅读803次,点赞0次
- FFmpeg - 常用的视频像素格式以及使用SwsContext和sws_scale进行视频像素格式转换和视频缩放 阅读191次,点赞0次
- FFmpeg - FFmpeg历史版本下载和函数弃用列表 阅读424次,点赞0次
- Python - 使用ffmepg批量转换某个文件夹以及所有子文件夹下所有的视频,修改其帧率/码率/分辨率到另一文件夹,并保留原有文件夹结构 阅读1794次,点赞0次
- Ubuntu编译安装FFmpeg+libx264以及编译+安装Opencv+FFmpeg保姆教程 阅读765次,点赞1次
- OpenCV/FFmpeg - 使用FFmpeg编码OpenCV中的BGR视频流为H264视频流以及解码H264视频流为OpenCV中的BGR视频流 阅读318次,点赞0次
- FFmpeg - 通过h264编码的视频文件开始很清晰后面逐渐模糊 阅读2719次,点赞1次
- FFmpeg - 音频处理基本概念以及音频重采样(采样率转换) 阅读3804次,点赞0次
- FFmpeg - 将某个文件夹下的图片按标号顺序合成为指定编码格式和指定帧率的视频 阅读2845次,点赞0次
- FFmpeg - RGB图像编码为h264出现垂直旋转的问题 阅读2615次,点赞0次
全站随机文章推荐
- C++11 - 封装std::thread,增加子线程启动、暂停、唤起、停止功能 阅读2003次,点赞0次
- C++ - 字节数组byte[]或者unsigned char[]与double的相互转换 阅读599次,点赞0次
- 我的开源项目 - 各种搜索引擎收录查询接口(Google/百度/必应/360/搜狗......) 阅读3436次,点赞3次
- 资源分享 - Computer Graphics - From Pixels to Programmable Graphics Hardware 英文高清PDF下载 阅读460次,点赞1次
- C++ - 常用的C++命令行参数解析第三方库 阅读321次,点赞0次
- WordPress - get_post_type():获取当前文章或者给定文章类型 阅读1600次,点赞0次
- C++11 - 构建一个符合实际应用要求的线程池 阅读688次,点赞0次
- 资源分享 - GPU Pro 360 - Guide to Image Space 英文高清PDF下载 阅读1370次,点赞0次
- 资源分享 - 3D Engine Design for Virtual Globes 英文高清PDF下载 阅读1183次,点赞0次
- 资源分享 - Advanced High Dynamic Range Imaging, Second Edition 英文高清PDF下载 阅读832次,点赞0次
评论
153