将mat yuv编码为h264流, 使用ffmpeg, cpp代码, 以函数形式
时间: 2024-06-11 11:08:55 浏览: 102
ffmpeg YUV编码成h264
以下是将mat yuv编码为h264流的cpp代码,使用ffmpeg库:
```cpp
#include <iostream>
#include <string>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
using namespace std;
using namespace cv;
// Function to encode a YUV image to H264 stream
int encode_yuv_to_h264(Mat yuv_frame, AVCodecContext* codec_ctx, AVFrame* frame, AVPacket* pkt, FILE* outfile) {
// Set the frame's data pointers to the YUV image data
frame->data[0] = yuv_frame.data;
frame->data[1] = yuv_frame.data + yuv_frame.rows * yuv_frame.cols;
frame->data[2] = yuv_frame.data + yuv_frame.rows * yuv_frame.cols * 5 / 4;
// Set the frame's line sizes to the YUV image line sizes
frame->linesize[0] = yuv_frame.cols;
frame->linesize[1] = yuv_frame.cols / 2;
frame->linesize[2] = yuv_frame.cols / 2;
// Encode the frame and write the packet to the output file
int ret = avcodec_send_frame(codec_ctx, frame);
if (ret < 0) {
cerr << "Error sending frame to encoder: " << av_err2str(ret) << endl;
return ret;
}
while (ret >= 0) {
ret = avcodec_receive_packet(codec_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
return 0;
} else if (ret < 0) {
cerr << "Error receiving packet from encoder: " << av_err2str(ret) << endl;
return ret;
}
fwrite(pkt->data, 1, pkt->size, outfile);
av_packet_unref(pkt);
}
return 0;
}
int main(int argc, char* argv[]) {
if (argc < 4) {
cerr << "Usage: " << argv[0] << " <input_yuv_file> <output_h264_file> <output_width> <output_height>" << endl;
return 1;
}
// Open the input file and read the YUV image
FILE* infile = fopen(argv[1], "rb");
if (!infile) {
cerr << "Could not open input file: " << argv[1] << endl;
return 1;
}
int width = stoi(argv[3]);
int height = stoi(argv[4]);
Mat yuv_frame(height * 3 / 2, width, CV_8UC1);
fread(yuv_frame.data, 1, yuv_frame.total(), infile);
fclose(infile);
// Initialize the FFmpeg library
avcodec_register_all();
AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec) {
cerr << "Could not find H264 encoder" << endl;
return 1;
}
AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
cerr << "Could not allocate codec context" << endl;
return 1;
}
// Set the codec context parameters
codec_ctx->width = width;
codec_ctx->height = height;
codec_ctx->time_base = {1, 25};
codec_ctx->framerate = {25, 1};
codec_ctx->gop_size = 10;
codec_ctx->max_b_frames = 1;
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
cerr << "Could not open codec" << endl;
return 1;
}
// Create the output file and write the H264 stream header
FILE* outfile = fopen(argv[2], "wb");
if (!outfile) {
cerr << "Could not open output file: " << argv[2] << endl;
return 1;
}
AVFrame* frame = av_frame_alloc();
frame->format = codec_ctx->pix_fmt;
frame->width = codec_ctx->width;
frame->height = codec_ctx->height;
av_frame_get_buffer(frame, 0);
AVPacket* pkt = av_packet_alloc();
av_init_packet(pkt);
avcodec_send_frame(codec_ctx, nullptr);
while (avcodec_receive_packet(codec_ctx, pkt) == 0) {
fwrite(pkt->data, 1, pkt->size, outfile);
av_packet_unref(pkt);
}
// Encode the YUV image to H264 stream and write the output packets to the output file
encode_yuv_to_h264(yuv_frame, codec_ctx, frame, pkt, outfile);
// Flush the encoder and write any remaining packets to the output file
while (avcodec_receive_packet(codec_ctx, pkt) == 0) {
fwrite(pkt->data, 1, pkt->size, outfile);
av_packet_unref(pkt);
}
// Close the output file and free resources
fclose(outfile);
av_packet_free(&pkt);
av_frame_free(&frame);
avcodec_free_context(&codec_ctx);
return 0;
}
```
该代码中的主要函数是`encode_yuv_to_h264`,该函数接受一个`Mat`类型的YUV图像,一个AVCodecContext结构体指针,一个AVFrame结构体指针和一个AVPacket结构体指针,以及一个输出文件指针。该函数将YUV图像编码为H264流,并将输出数据写入输出文件。
要使用此代码,请将其保存为文件(例如“yuv_to_h264.cpp”),并使用以下命令编译:
```
g++ -o yuv_to_h264 yuv_to_h264.cpp `pkg-config --cflags --libs opencv` -lavcodec -lavutil
```
在编译后,您可以使用以下命令将YUV文件编码为H264文件:
```
./yuv_to_h264 input.yuv output.h264 width height
```
其中,`input.yuv`是输入YUV文件的路径,`output.h264`是输出H264文件的路径,`width`和`height`是输出视频的宽度和高度。
阅读全文