西安手机网站,市场营销ppt模板,软考高项彻底没用了,施工建设集团网站前言 测试环境#xff1a;
ffmpeg的4.3.2自行编译版本windows环境qt5.12
使用H.264编码对YUV视频进行压缩
ffmpeg -s 640x480 -pix_fmt yuv420p -i in.yuv -c:v libx264 out.h264
-c:v libx264是指定使用libx264作为编码器完整代码#xff1a;
H264EncodeThread.h
#ifnd…前言 测试环境
ffmpeg的4.3.2自行编译版本windows环境qt5.12
使用H.264编码对YUV视频进行压缩
ffmpeg -s 640x480 -pix_fmt yuv420p -i in.yuv -c:v libx264 out.h264
-c:v libx264是指定使用libx264作为编码器完整代码
H264EncodeThread.h
#ifndef H264ENCODETHREAD_H
#define H264ENCODETHREAD_H#include QObject
#include QThreadextern C {
#include libavutil/avutil.h
}typedef struct {const char *filename;int width;int height;AVPixelFormat pixFmt;int fps;
} VideoEncodeSpec;class H264EncodeThread : public QThread
{Q_OBJECT
public:explicit H264EncodeThread(QObject *parent nullptr);~H264EncodeThread();static void h264Encode(VideoEncodeSpec in,const char *outFilename);signals:// QThread interface
protected:virtual void run() override;
};#endif // H264ENCODETHREAD_HH264EncodeThread.cpp
#include h264encodethread.hextern C {
#include libavcodec/avcodec.h
#include libavutil/avutil.h
#include libavutil/imgutils.h
}#include QDebug
#include QFile#define ERROR_BUF(ret) \char errbuf[1024]; \av_strerror(ret, errbuf, sizeof (errbuf));H264EncodeThread::H264EncodeThread(QObject *parent) : QThread(parent)
{// 当监听到线程结束时finished就调用deleteLater回收内存connect(this,H264EncodeThread::finished,this,[](){this-deleteLater();qDebug()RecordPcmThread线程结束线程指针被dlete;});
}H264EncodeThread::~H264EncodeThread()
{// 断开所有的连接disconnect();//强制关闭窗口时线程也能安全关闭requestInterruption();wait();qDebug()RecordPcmThread析构函数;
}// 检查像素格式
static int check_pix_fmt(const AVCodec *codec,enum AVPixelFormat pixFmt) {const enum AVPixelFormat *p codec-pix_fmts;while (*p ! AV_PIX_FMT_NONE) {if (*p pixFmt) return 1;qDebug()*p;p;}return 0;
}// 返回负数中途出现了错误
// 返回0编码操作正常完成
static int encode(AVCodecContext *ctx,AVFrame *frame,AVPacket *pkt,QFile outFile) {// 发送数据到编码器int ret avcodec_send_frame(ctx, frame);if (ret 0) {ERROR_BUF(ret);qDebug() avcodec_send_frame error errbuf;return ret;}// 不断从编码器中取出编码后的数据while (true) {ret avcodec_receive_packet(ctx, pkt);if (ret AVERROR(EAGAIN) || ret AVERROR_EOF) {// 继续读取数据到frame然后送到编码器return 0;} else if (ret 0) { // 其他错误return ret;}// 成功从编码器拿到编码后的数据// 将编码后的数据写入文件outFile.write((char *) pkt-data, pkt-size);// 释放pkt内部的资源av_packet_unref(pkt);}
}void H264EncodeThread::h264Encode(VideoEncodeSpec in, const char *outFilename)
{// 文件QFile inFile(in.filename);QFile outFile(outFilename);// 一帧图片的大小int imgSize av_image_get_buffer_size(in.pixFmt, in.width, in.height, 1);// 返回结果int ret 0;// 编码器AVCodec *codec nullptr;// 编码上下文AVCodecContext *ctx nullptr;// 存放编码前的数据yuvAVFrame *frame nullptr;// 存放编码后的数据h264AVPacket *pkt nullptr;// uint8_t *buf nullptr;// 获取编码器//codec avcodec_find_encoder_by_name(libx264);codec avcodec_find_encoder(AV_CODEC_ID_H264);if (!codec) {qDebug() encoder not found;return;}// 检查输入数据的采样格式if (!check_pix_fmt(codec, in.pixFmt)) {qDebug() unsupported pixel format av_get_pix_fmt_name(in.pixFmt);return;}// 创建编码上下文ctx avcodec_alloc_context3(codec);if (!ctx) {qDebug() avcodec_alloc_context3 error;return;}// 设置yuv参数ctx-width in.width;ctx-height in.height;ctx-pix_fmt in.pixFmt;//手动设置gop的数量//ctx-gop_size5;// 设置帧率1秒钟显示的帧数是in.fpsctx-time_base {1, in.fps};// 打开编码器ret avcodec_open2(ctx, codec, nullptr);if (ret 0) {ERROR_BUF(ret);qDebug() avcodec_open2 error errbuf;goto end;}// 创建AVFrameframe av_frame_alloc();if (!frame) {qDebug() av_frame_alloc error;goto end;}frame-width ctx-width;frame-height ctx-height;frame-format ctx-pix_fmt;frame-pts 0;// 利用width、height、format创建缓冲区ret av_image_alloc(frame-data, frame-linesize,in.width, in.height, in.pixFmt, 1);if (ret 0) {ERROR_BUF(ret);qDebug() av_frame_get_buffer error errbuf;goto end;}// 创建输入缓冲区方法2
// buf (uint8_t *) av_malloc(imgSize);
// ret av_image_fill_arrays(frame-data, frame-linesize,
// buf,
// in.pixFmt, in.width, in.height, 1);
// if (ret 0) {
// ERROR_BUF(ret);
// qDebug() av_image_fill_arrays error errbuf;
// goto end;
// }
// qDebug() buf frame-data[0];// 创建输入缓冲区方法3
// ret av_frame_get_buffer(frame, 0);
// if (ret 0) {
// ERROR_BUF(ret);
// qDebug() av_frame_get_buffer error errbuf;
// goto end;
// }// 创建AVPacketpkt av_packet_alloc();if (!pkt) {qDebug() av_packet_alloc error;goto end;}// 打开文件if (!inFile.open(QFile::ReadOnly)) {qDebug() file open error in.filename;goto end;}if (!outFile.open(QFile::WriteOnly)) {qDebug() file open error outFilename;goto end;}// 读取数据到frame中while ((ret inFile.read((char *) frame-data[0],imgSize)) 0) {// 进行编码if (encode(ctx, frame, pkt, outFile) 0) {goto end;}// 设置帧的序号frame-pts;}// 刷新缓冲区encode(ctx, nullptr, pkt, outFile);end:// 关闭文件inFile.close();outFile.close();// av_freep(buf);// 释放资源if (frame) {av_freep(frame-data[0]);
// av_free(frame-data[0]);
// frame-data[0] nullptr;av_frame_free(frame);}av_packet_free(pkt);avcodec_free_context(ctx);qDebug() 线程正常结束;
}void H264EncodeThread::run()
{VideoEncodeSpec in;in.filename E:/media/out-yuv420p.yuv;in.width 640;in.height 480;in.fps 30;in.pixFmt AV_PIX_FMT_YUV420P;h264Encode(in, E:/media/out-yuv420p.h264);
}线程调用
void MainWindow::on_pushButton_h264_encode_clicked()
{m_pH264EncodeThreadnew H264EncodeThread(this);m_pH264EncodeThread-start();
}注意.h文件中提前声明了以下全局变量 H264EncodeThread *m_pH264EncodeThreadnullptr;注意本文为个人记录新手照搬可能会出现各种问题请谨慎使用 码字不易如果这篇博客对你有帮助麻烦点赞收藏非常感谢有不对的地方