c++ Mat 转 h264
时间: 2023-10-09 14:09:56 浏览: 89
要将 OpenCV 的 Mat 类型转换成 H.264 格式的视频,需要使用 FFmpeg 库。以下是一个简单的示例代码,可以将 Mat 类型的视频转换成 H.264 格式的视频:
```c++
#include <iostream>
#include <opencv2/opencv.hpp>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libswscale/swscale.h>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
// OpenCV video capture
VideoCapture cap("video.mp4");
if (!cap.isOpened())
{
cerr << "Failed to open video file!" << endl;
return -1;
}
// FFmpeg encoder
avcodec_register_all();
AVCodec* codec = avcodec_find_encoder_by_name("libx264");
if (!codec)
{
cerr << "Codec not found!" << endl;
return -1;
}
AVCodecContext* codecCtx = avcodec_alloc_context3(codec);
if (!codecCtx)
{
cerr << "Failed to allocate codec context!" << endl;
return -1;
}
codecCtx->bit_rate = 400000;
codecCtx->width = cap.get(CAP_PROP_FRAME_WIDTH);
codecCtx->height = cap.get(CAP_PROP_FRAME_HEIGHT);
codecCtx->time_base = (AVRational){1, 25};
codecCtx->gop_size = 10;
codecCtx->max_b_frames = 1;
codecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
int ret = avcodec_open2(codecCtx, codec, NULL);
if (ret < 0)
{
cerr << "Failed to open codec: " << av_err2str(ret) << endl;
return -1;
}
// FFmpeg video output
AVFormatContext* fmtCtx = NULL;
ret = avformat_alloc_output_context2(&fmtCtx, NULL, NULL, "output.mp4");
if (ret < 0)
{
cerr << "Failed to allocate output context: " << av_err2str(ret) << endl;
return -1;
}
AVOutputFormat* fmt = fmtCtx->oformat;
if (fmt->video_codec == AV_CODEC_ID_NONE)
{
cerr << "No video codec found!" << endl;
return -1;
}
AVStream* stream = avformat_new_stream(fmtCtx, NULL);
if (!stream)
{
cerr << "Failed to allocate stream!" << endl;
return -1;
}
AVCodecContext* streamCtx = avcodec_alloc_context3(codec);
if (!streamCtx)
{
cerr << "Failed to allocate codec context!" << endl;
return -1;
}
ret = avcodec_parameters_from_context(stream->codecpar, streamCtx);
if (ret < 0)
{
cerr << "Failed to copy codec parameters: " << av_err2str(ret) << endl;
return -1;
}
stream->time_base = (AVRational){1, 25};
// Open output file
ret = avio_open(&fmtCtx->pb, "output.mp4", AVIO_FLAG_WRITE);
if (ret < 0)
{
cerr << "Failed to open output file: " << av_err2str(ret) << endl;
return -1;
}
// Write header
ret = avformat_write_header(fmtCtx, NULL);
if (ret < 0)
{
cerr << "Failed to write header: " << av_err2str(ret) << endl;
return -1;
}
SwsContext* swsCtx = sws_getContext(codecCtx->width, codecCtx->height, AV_PIX_FMT_BGR24,
codecCtx->width, codecCtx->height, codecCtx->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
AVFrame* frame = av_frame_alloc();
frame->format = codecCtx->pix_fmt;
frame->width = codecCtx->width;
frame->height = codecCtx->height;
ret = av_frame_get_buffer(frame, 0);
if (ret < 0)
{
cerr << "Failed to allocate frame buffer: " << av_err2str(ret) << endl;
return -1;
}
AVPacket packet;
av_init_packet(&packet);
packet.data = NULL;
packet.size = 0;
while (true)
{
Mat frameMat;
cap >> frameMat;
if (frameMat.empty())
break;
// Convert OpenCV Mat to FFmpeg AVFrame
AVFrame* inputFrame = av_frame_alloc();
inputFrame->format = AV_PIX_FMT_BGR24;
inputFrame->width = frameMat.cols;
inputFrame->height = frameMat.rows;
ret = av_frame_get_buffer(inputFrame, 0);
if (ret < 0)
{
cerr << "Failed to allocate frame buffer: " << av_err2str(ret) << endl;
return -1;
}
uint8_t* inputData[AV_NUM_DATA_POINTERS] = {0};
inputData[0] = (uint8_t*)frameMat.data;
int inputLinesize[AV_NUM_DATA_POINTERS] = {0};
inputLinesize[0] = frameMat.step;
sws_scale(swsCtx, inputData, inputLinesize, 0, frameMat.rows, inputFrame->data, inputFrame->linesize);
// Encode frame
ret = avcodec_send_frame(codecCtx, inputFrame);
if (ret < 0)
{
cerr << "Failed to send frame: " << av_err2str(ret) << endl;
return -1;
}
while (ret >= 0)
{
ret = avcodec_receive_packet(codecCtx, &packet);
if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
{
cerr << "Failed to receive packet: " << av_err2str(ret) << endl;
return -1;
}
if (ret >= 0)
{
av_packet_rescale_ts(&packet, codecCtx->time_base, stream->time_base);
packet.stream_index = stream->index;
ret = av_interleaved_write_frame(fmtCtx, &packet);
if (ret < 0)
{
cerr << "Failed to write packet: " << av_err2str(ret) << endl;
return -1;
}
av_packet_unref(&packet);
}
}
av_frame_unref(inputFrame);
}
// Flush encoder
ret = avcodec_send_frame(codecCtx, NULL);
if (ret < 0)
{
cerr << "Failed to send frame: " << av_err2str(ret) << endl;
return -1;
}
while (ret >= 0)
{
ret = avcodec_receive_packet(codecCtx, &packet);
if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
{
cerr << "Failed to receive packet: " << av_err2str(ret) << endl;
return -1;
}
if (ret >= 0)
{
av_packet_rescale_ts(&packet, codecCtx->time_base, stream->time_base);
packet.stream_index = stream->index;
ret = av_interleaved_write_frame(fmtCtx, &packet);
if (ret < 0)
{
cerr << "Failed to write packet: " << av_err2str(ret) << endl;
return -1;
}
av_packet_unref(&packet);
}
}
// Write trailer
av_write_trailer(fmtCtx);
// Cleanup
avcodec_free_context(&codecCtx);
avcodec_free_context(&streamCtx);
av_frame_free(&frame);
avformat_free_context(fmtCtx);
return 0;
}
```
这段代码使用 OpenCV 从视频文件中读取每一帧图像,然后使用 FFmpeg 编码器将其转换成 H.264 格式,并写入输出文件。要使用此代码,需要先安装 FFmpeg 库并将其头文件和库文件路径添加到编译器的 include 和 lib 路径中。
阅读全文