c++ ffmpeg4.1 cv::mat 转 AV_PIX_FMT_YUV420P 代码
时间: 2024-03-17 22:42:28 浏览: 133
C++下纯代码NV12转换YUV420和YUV444内附实例,可以直接运行
以下是一个简单的示例代码,可以将 OpenCV 的 `cv::Mat` 对象转换为 FFmpeg 的 `AVFrame`,并将其编码为 YUV 420P 格式。
```c++
#include <opencv2/opencv.hpp>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
int main() {
// 初始化 FFmpeg
av_register_all();
// 创建格式上下文
AVFormatContext* format_ctx = avformat_alloc_context();
if (!format_ctx) {
std::cerr << "Failed to allocate format context" << std::endl;
return -1;
}
// 设置输出格式
AVOutputFormat* output_fmt = av_guess_format("mp4", nullptr, nullptr);
if (!output_fmt) {
std::cerr << "Failed to guess output format" << std::endl;
return -1;
}
format_ctx->oformat = output_fmt;
// 打开输出文件
AVIOContext* io_ctx = nullptr;
if (avio_open(&io_ctx, "output.mp4", AVIO_FLAG_WRITE) < 0) {
std::cerr << "Failed to open output file" << std::endl;
return -1;
}
format_ctx->pb = io_ctx;
// 创建视频流
AVStream* video_stream = avformat_new_stream(format_ctx, nullptr);
if (!video_stream) {
std::cerr << "Failed to create video stream" << std::endl;
return -1;
}
// 设置编码器参数
AVCodecParameters* codec_params = video_stream->codecpar;
codec_params->codec_type = AVMEDIA_TYPE_VIDEO;
codec_params->codec_id = output_fmt->video_codec;
codec_params->width = 640;
codec_params->height = 480;
codec_params->format = AV_PIX_FMT_YUV420P;
// 查找编码器
AVCodec* codec = avcodec_find_encoder(output_fmt->video_codec);
if (!codec) {
std::cerr << "Failed to find encoder" << std::endl;
return -1;
}
// 创建编码器上下文
AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
std::cerr << "Failed to allocate codec context" << std::endl;
return -1;
}
codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
codec_ctx->width = codec_params->width;
codec_ctx->height = codec_params->height;
codec_ctx->pix_fmt = codec_params->format;
codec_ctx->time_base = {1, 25};
// 打开编码器
if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
std::cerr << "Failed to open codec" << std::endl;
return -1;
}
// 创建帧
AVFrame* frame = av_frame_alloc();
if (!frame) {
std::cerr << "Failed to allocate frame" << std::endl;
return -1;
}
frame->format = codec_ctx->pix_fmt;
frame->width = codec_ctx->width;
frame->height = codec_ctx->height;
// 分配帧数据空间
if (av_frame_get_buffer(frame, 0) < 0) {
std::cerr << "Failed to allocate frame data" << std::endl;
return -1;
}
// 创建格式转换器
SwsContext* sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, AV_PIX_FMT_BGR24,
codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt,
SWS_BICUBIC, nullptr, nullptr, nullptr);
if (!sws_ctx) {
std::cerr << "Failed to create format converter" << std::endl;
return -1;
}
// 读取输入帧
cv::Mat input_frame = cv::imread("input.jpg");
if (input_frame.empty()) {
std::cerr << "Failed to read input frame" << std::endl;
return -1;
}
// 转换输入帧
uint8_t* input_data[AV_NUM_DATA_POINTERS] = {0};
input_data[0] = input_frame.data;
int input_linesize[AV_NUM_DATA_POINTERS] = {0};
input_linesize[0] = input_frame.step;
sws_scale(sws_ctx, input_data, input_linesize, 0, codec_ctx->height, frame->data, frame->linesize);
// 编码帧
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = nullptr;
pkt.size = 0;
int got_packet = 0;
if (avcodec_encode_video2(codec_ctx, &pkt, frame, &got_packet) < 0) {
std::cerr << "Failed to encode frame" << std::endl;
return -1;
}
// 写入输出文件
if (got_packet) {
av_packet_rescale_ts(&pkt, codec_ctx->time_base, video_stream->time_base);
pkt.stream_index = video_stream->index;
if (av_interleaved_write_frame(format_ctx, &pkt) < 0) {
std::cerr << "Failed to write packet" << std::endl;
return -1;
}
av_packet_unref(&pkt);
}
// 写入文件尾
av_write_trailer(format_ctx);
// 释放资源
avcodec_free_context(&codec_ctx);
av_frame_free(&frame);
avio_closep(&format_ctx->pb);
avformat_free_context(format_ctx);
sws_freeContext(sws_ctx);
return 0;
}
```
需要注意的是,上述代码中的 `AV_PIX_FMT_BGR24` 表示输入图像的像素格式,如果您的输入图像格式不是 BGR24,需要相应地修改代码。另外,上述代码中的像素格式硬编码为 YUV420P,如果您需要使用其他像素格式,也需要相应地修改代码。
阅读全文