添加编译依赖
INCLUDEPATH += /home/×××/Downloads/ffmpeg-4.3.2/build/FFmpeg/include
LIBS += -L /home/×××/Downloads/ffmpeg-4.3.2/build/FFmpeg/lib \
-lavcodec \
-lavdevice \
-lavfilter \
-lavformat \
-lavutil \
-lswresample \
-lswscale
关键代码
#ifndef FFMPEGMANAGER_H
#define FFMPEGMANAGER_H
#include <QString>
#include <QFile>
#include <QDebug>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
}
typedef struct {
QString filename;
QString h264name;
int width;
int height;
AVPixelFormat format;
int fps;
} VideoEncodeSpec;
typedef void*(*handler_t)(void*);
class FfmpegManager
{
public:
FfmpegManager();
bool testYuv2H264(QString& yuvFile,QString& destFile);
void start();
static void* h264Encode(void *);
handler_t callback;
};
#endif
#include "ffmpegmanager.h"
FfmpegManager::FfmpegManager()
{
}
bool FfmpegManager::testYuv2H264(QString& yuvFile,QString& destFile){
}
void FfmpegManager::start(){
pthread_t tid;
QString yuv("/home/×××/qt/waterfall_cif.yuv");
QString desth264("/home/×××/qt/waterfall_cif_f2.h264");
VideoEncodeSpec in;
in.filename = yuv.toLatin1().data();
in.h264name = desth264.toLatin1().data();
in.width = 352;
in.height = 288;
in.fps = 30;
in.format = AV_PIX_FMT_YUV420P;
pthread_create(&tid,NULL,h264Encode,&in);
}
#define ERROR_BUF(ret) \
char errbuf[1024]; \
av_strerror(ret, errbuf, sizeof (errbuf));
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;
p++;
}
return 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) {
return 0;
} else if (ret < 0) {
ERROR_BUF(ret);
qDebug() << "avcodec_receive_packet error" << errbuf;
return ret;
}
outFile.write((char *) pkt->data, pkt->size);
av_packet_unref(pkt);
}
return 0;
}
void* FfmpegManager::h264Encode(void *inArg){
VideoEncodeSpec in = *static_cast<VideoEncodeSpec *>(inArg);
QFile inFile(in.filename);
QFile outFile(in.h264name);
int imgSize = av_image_get_buffer_size(in.format,in.width,in.height,1);
int ret = 0;
AVCodec *codec = nullptr;
AVCodecContext *ctx = nullptr;
AVFrame *frame = nullptr;
AVPacket *pkt = nullptr;
codec = avcodec_find_encoder(AV_CODEC_ID_H264);
qDebug() << "codec.name:" << codec->name<<",codec.id:"<<codec->id;
if(!codec){
qDebug() << "encoder not found";
return NULL;
}
if(!check_pix_fmt(codec,in.format)){
qDebug() << "Encoder does not support pixel format"
<< av_get_pix_fmt_name(in.format);
return NULL;
}
ctx = avcodec_alloc_context3(codec);
if (!ctx) {
qDebug() << "avcodec_alloc_context3 error";
return NULL;
}
ctx->width = in.width;
ctx->height = in.height;
ctx->pix_fmt = in.format;
ctx->time_base = {1,in.fps};
ret = avcodec_open2(ctx,codec,nullptr);
if (ret < 0) {
ERROR_BUF(ret);
qDebug() << "avcodec_open2 error" << errbuf;
goto end;
}
frame = 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;
ret = av_image_alloc(frame->data,frame->linesize,in.width,in.height,in.format,1);
if (ret < 0) {
ERROR_BUF(ret);
qDebug() << "av_frame_get_buffer error" << errbuf;
goto end;
}
qDebug() << frame->data[0] << frame->data[1] << frame->data[2];
pkt = 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" << in.h264name;
goto end;
}
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();
if(frame){
av_freep(&frame->data[0]);
av_frame_free(&frame);
}
av_packet_free(&pkt);
avcodec_free_context(&ctx);
qDebug()<<"ffmpeg encode finished"<<endl;
}
编码
FfmpegManager ffmpegManager
ffmpegManager.start()
测试结果

