c++ Mat 转 h264
时间: 2023-10-09 14:09:56 浏览: 285
C++ 使用Intel Media SDK 实现H.264硬编码
5星 · 资源好评率100%
要将一个 OpenCV 的 Mat 对象转换成 H.264 格式的视频流,你可以使用 FFmpeg 库。FFmpeg 是一个开源的跨平台音视频编解码库,可以处理几乎所有常见的音视频格式。
下面是一个简单的示例代码,用于将一个 OpenCV 的 Mat 对象转换成 H.264 格式的视频流:
```c++
#include <opencv2/opencv.hpp>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
using namespace cv;
int main(int argc, char* argv[])
{
// 读取视频文件
VideoCapture cap("video.mp4");
if (!cap.isOpened()) {
printf("Failed to open video file\n");
return -1;
}
// 获取视频文件的宽度和高度
int width = cap.get(CAP_PROP_FRAME_WIDTH);
int height = cap.get(CAP_PROP_FRAME_HEIGHT);
// 创建一个 FFmpeg 的 AVFormatContext 对象,用于输出 H.264 格式的视频流
AVFormatContext* pFormatCtx = nullptr;
avformat_alloc_output_context2(&pFormatCtx, nullptr, nullptr, "output.mp4");
if (!pFormatCtx) {
printf("Failed to allocate output context\n");
return -1;
}
// 设置输出格式为 H.264
AVOutputFormat* pOutputFmt = pFormatCtx->oformat;
if (pOutputFmt->video_codec != AV_CODEC_ID_H264) {
printf("Output format does not support H.264\n");
return -1;
}
// 添加一个视频流到 AVFormatContext 对象中
AVCodec* pCodec = nullptr;
AVStream* pStream = avformat_new_stream(pFormatCtx, pCodec);
if (!pStream) {
printf("Failed to create video stream\n");
return -1;
}
// 设置视频流参数
pStream->codecpar->codec_id = pOutputFmt->video_codec;
pStream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
pStream->codecpar->width = width;
pStream->codecpar->height = height;
pStream->codecpar->format = AV_PIX_FMT_YUV420P;
pStream->codecpar->bit_rate = 400000;
// 打开视频编码器
AVCodecContext* pCodecCtx = avcodec_alloc_context3(pCodec);
avcodec_parameters_to_context(pCodecCtx, pStream->codecpar);
avcodec_open2(pCodecCtx, pCodec, nullptr);
// 创建一个 AVFrame 对象,用于存储从 OpenCV 的 Mat 对象中读取的像素数据
AVFrame* pFrame = av_frame_alloc();
pFrame->format = AV_PIX_FMT_YUV420P;
pFrame->width = width;
pFrame->height = height;
av_frame_get_buffer(pFrame, 0);
// 创建一个 SwsContext 对象,用于将 OpenCV 的 Mat 对象转换成 YUV420P 格式
SwsContext* pSwsCtx = sws_getContext(width, height, AV_PIX_FMT_BGR24,
width, height, AV_PIX_FMT_YUV420P,
SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
// 初始化 AVPacket 对象,用于存储编码后的视频数据
AVPacket pkt = { 0 };
av_init_packet(&pkt);
// 逐帧读取视频,进行编码和写入
Mat frame;
while (cap.read(frame)) {
// 将 OpenCV 的 Mat 对象转换成 AVFrame 对象
uint8_t* data[AV_NUM_DATA_POINTERS] = { 0 };
data[0] = frame.data;
int linesize[AV_NUM_DATA_POINTERS] = { static_cast<int>(frame.step) };
sws_scale(pSwsCtx, data, linesize, 0, height, pFrame->data, pFrame->linesize);
// 编码 AVFrame 对象
int ret = avcodec_send_frame(pCodecCtx, pFrame);
if (ret < 0) {
printf("Failed to send frame to encoder\n");
return -1;
}
while (ret >= 0) {
// 从编码器中获取编码后的视频数据
ret = avcodec_receive_packet(pCodecCtx, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
}
else if (ret < 0) {
printf("Failed to receive packet from encoder\n");
return -1;
}
// 写入编码后的视频数据
av_write_frame(pFormatCtx, &pkt);
av_packet_unref(&pkt);
}
}
// 刷新编码器
avcodec_send_frame(pCodecCtx, nullptr);
while (ret >= 0) {
ret = avcodec_receive_packet(pCodecCtx, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
}
else if (ret < 0) {
printf("Failed to receive packet from encoder\n");
return -1;
}
av_write_frame(pFormatCtx, &pkt);
av_packet_unref(&pkt);
}
// 写入文件尾
av_write_trailer(pFormatCtx);
// 释放资源
avcodec_close(pCodecCtx);
avcodec_free_context(&pCodecCtx);
av_frame_free(&pFrame);
sws_freeContext(pSwsCtx);
avio_closep(&pFormatCtx->pb);
avformat_free_context(pFormatCtx);
return 0;
}
```
这段代码仅供参考,如果你需要更多功能的支持,如编码参数设置、多线程编码、音视频混合等,你可能需要阅读 FFmpeg 的文档以获取更多帮助。
阅读全文