我在QT中想把一张图片合成视频,但是不知道为什么不成功:
```c
qDebug()<<"================================================================start======================================================================";
int ret;
QImage image("/sdcard/test.png");
int imagewidth = image.width();
int imageheight = image.height();
// 初始化 FFmpeg
qDebug()<<"avdevice_register_all()";
avdevice_register_all(); //初始化所有设备
qDebug()<<"formatContext = avformat_alloc_context()";
formatContext = avformat_alloc_context();//分配format上下文
QString outputFileName("/sdcard/ffmep.mp4");
qDebug()<<"avformat_alloc_output_context2(&formatContext, nullptr, nullptr, outputFileName.toUtf8().constData())";
ret = avformat_alloc_output_context2(&formatContext, nullptr, nullptr, outputFileName.toUtf8().constData());
qDebug()<<"ret===="<<ret;
qDebug()<<"formatContext===="<<formatContext;
if(!formatContext) //如果根据文件名没有找到对应的格式则默认mpeg格式
{
qDebug()<<"!formatContext ======mpeg";
ret = avformat_alloc_output_context2(&formatContext, NULL, "mpeg", outputFileName.toUtf8().constData()); //没有找到文件类型默认mpeg(MP4)
}
qDebug()<<"formatContext->oformat = av_guess_format(nullptr, outputFileName.toUtf8().constData(), nullptr);";
formatContext->oformat = av_guess_format(nullptr, outputFileName.toUtf8().constData(), nullptr);
qDebug() << "avio_open(&formatContext->pb, outputFileName.toUtf8().constData(), AVIO_FLAG_WRITE) < 0";
// 打开输出文件
if (avio_open(&formatContext->pb, outputFileName.toUtf8().constData(), AVIO_FLAG_WRITE) < 0) {
qDebug() << "Failed to open output file";
return;
}
qDebug() << "AVStream* stream = avformat_new_stream(formatContext, nullptr);";
// 创建一个AVStream对象
AVStream* stream = avformat_new_stream(formatContext, nullptr);
if (!stream) {
qDebug() << "Failed to create output stream";
return;
}
qDebug() << "AVCodecParameters* codecParameters = stream->codecpar;";
// 配置AVCodecContext
AVCodecParameters* codecParameters = stream->codecpar;
codecParameters->codec_type = AVMEDIA_TYPE_VIDEO;
codecParameters->codec_id = AV_CODEC_ID_H264; // 使用H.264编码器
codecParameters->width = imagewidth;
codecParameters->height = imageheight;
qDebug() << " const AVCodec* codec = avcodec_find_encoder(codecParameters->codec_id);";
qDebug() << "const AVCodec* codec = avcodec_find_encoder(codecParameters->codec_id);";
// 打开编解码器
const AVCodec* codec = avcodec_find_encoder(codecParameters->codec_id);
AVCodecContext* codecContext = avcodec_alloc_context3(codec);
codecContext->width = imagewidth;
codecContext->height = imageheight;
codecContext->pix_fmt = AV_PIX_FMT_YUV420P;
codecContext->time_base = {1, 30}; // 设置编码器的时间基为 1秒/30帧
qDebug() << "AV_PIX_FMT_YUV420P====="<<AV_PIX_FMT_YUV420P;
qDebug() << "codecContext->pix_fmt====="<<codecContext->pix_fmt;
qDebug() << "avcodec_open2(codecContext, codec, nullptr);";
//设置完成编码格式以后要立刻打开,要不然调用avcodec_parameters_to_context的时候会重置编码
ret = avcodec_open2(codecContext, codec, nullptr);
if(ret < 0){
qDebug() << "Failed to avcodec_open2";
return;
}
qDebug() << "avcodec_parameters_to_context(codecContext, codecParameters);";
// 将编码器参数复制到输出流
avcodec_parameters_to_context(codecContext, codecParameters);
// 检查编解码器支持的像素格式
const AVPixelFormat* pixFmt = codec->pix_fmts;
qDebug() << "while";
while (*pixFmt != AV_PIX_FMT_NONE) {
qDebug() << av_get_pix_fmt_name(*pixFmt);
++pixFmt;
}
qDebug() << " avformat_write_header(formatContext, nullptr);";
// 写入头部信息
avformat_write_header(formatContext, nullptr);
qDebug() << " AVFrame* frame = av_frame_alloc();";
// 逐个写入图像帧
AVFrame* frame = av_frame_alloc();
if (!frame) {
qDebug() << "Failed to allocate frame.";
return;
}
qDebug() << "frame->format = AV_PIX_FMT_YUV420P";
frame->format = AV_PIX_FMT_YUV420P;
frame->width = imagewidth;
frame->height = imageheight;
qDebug() << "av_frame_get_buffer(frame, 32)";
if (av_frame_get_buffer(frame, 0) < 0) {
qDebug() << "Failed to allocate frame buffer.";
av_frame_free(&frame);
return;
}
qDebug() << "SwsContext* swsContext sws_getContext()";
// 图像格式转换
SwsContext* swsContext = sws_getContext(imagewidth, imageheight, AV_PIX_FMT_BGR32,
frame->width, frame->height, AV_PIX_FMT_YUV420P,
SWS_BICUBIC, nullptr, nullptr, nullptr);
if (!swsContext) {
qDebug() << "Failed to create SwsContext.";
av_frame_free(&frame);
return;
}
uint8_t* destData[4] = {frame->data[0], frame->data[1], frame->data[2], nullptr};
int destLinesize[4] = {frame->linesize[0], frame->linesize[1], frame->linesize[2], 0};
qDebug() << "int destLinesize[4] = {frame->linesize[0], frame->linesize[1], frame->linesize[2], 0};";
image = image.convertToFormat(QImage::Format_RGB32);
const uchar* bits = image.constBits();
int bytesPerLine = image.bytesPerLine();
qDebug() << "sws_scale(swsContext, &bits, &bytesPerLine, 0, image.height(), destData, destLinesize);";
sws_scale(swsContext, &bits, &bytesPerLine, 0, image.height(), destData, destLinesize);
qDebug() << "sws_freeContext(swsContext);";
sws_freeContext(swsContext);
qDebug() << "frame->pts = av_rescale_q(stream->nb_frames, stream->time_base, codecContext->time_base);;";
frame->pts = av_rescale_q(stream->nb_frames, stream->time_base, codecContext->time_base);
qDebug() << "AVPacket packet;";
// 编码并写入视频帧
AVPacket packet;
av_init_packet(&packet);
//packet.data = nullptr;
//packet.size = 0;
qDebug() << "avcodec_send_frame(codecContext, frame)";
if (avcodec_send_frame(codecContext, frame) < 0) {
qDebug() << "Failed to send frame for encoding.";
av_frame_free(&frame);
return;
}
qDebug() << "avcodec_receive_packet===="<<avcodec_receive_packet(codecContext, &packet);
// 接收输出包
while (true) {
int ret = avcodec_receive_packet(codecContext, &packet);
qDebug() << "ret=============="<<ret;
if (ret == AVERROR(EAGAIN)) {
// 需要更多输入数据,继续发送帧
qDebug() << "ret == AVERROR(EAGAIN)=============="<<AVERROR(EAGAIN);
break;
} else if (ret < 0) {
qDebug() << "Failed to receive packet.";
av_frame_free(&frame);
return;
}
// 处理输出包
av_interleaved_write_frame(formatContext, &packet);
av_packet_unref(&packet);
}
qDebug() << "av_write_trailer(formatContext)==="<<av_write_trailer(formatContext);;
qDebug() << "av_frame_free(&frame);";
av_frame_free(&frame);
qDebug()<<"=============================================================stop=========================================================================";
以下是我的log:
```c
================================================================start======================================================================
avdevice_register_all()
formatContext = avformat_alloc_context()
avformat_alloc_output_context2(&formatContext, nullptr, nullptr, outputFileName.toUtf8().constData())
ret==== 0
formatContext==== 0x2f5ff770
formatContext->oformat = av_guess_format(nullptr, outputFileName.toUtf8().constData(), nullptr);
avio_open(&formatContext->pb, outputFileName.toUtf8().constData(), AVIO_FLAG_WRITE) < 0
AVStream* stream = avformat_new_stream(formatContext, nullptr);
AVCodecParameters* codecParameters = stream->codecpar;
const AVCodec* codec = avcodec_find_encoder(codecParameters->codec_id);
const AVCodec* codec = avcodec_find_encoder(codecParameters->codec_id);
AV_PIX_FMT_YUV420P===== 0
codecContext->pix_fmt===== 0
avcodec_open2(codecContext, codec, nullptr);
[libx264 @ 0x2f5ffec0] using cpu capabilities: none!
[libx264 @ 0x2f5ffec0] profile High, level 4.0, 4:2:0, 8-bit
avcodec_parameters_to_context(codecContext, codecParameters);
while
yuv420p
yuvj420p
yuv422p
yuvj422p
yuv444p
yuvj444p
nv12
nv16
nv21
yuv420p10le
yuv422p10le
yuv444p10le
nv20le
gray
gray10le
avformat_write_header(formatContext, nullptr);
AVFrame* frame = av_frame_alloc();
frame->format = AV_PIX_FMT_YUV420P
av_frame_get_buffer(frame, 32)
SwsContext* swsContext sws_getContext()
int destLinesize[4] = {frame->linesize[0], frame->linesize[1], frame->linesize[2], 0};
sws_scale(swsContext, &bits, &bytesPerLine, 0, image.height(), destData, destLinesize);
sws_freeContext(swsContext);
frame->pts = av_rescale_q(stream->nb_frames, stream->time_base, codecContext->time_base);;
AVPacket packet;
avcodec_send_frame(codecContext, frame)
avcodec_receive_packet==== -11
ret============== -11
ret == AVERROR(EAGAIN)============== -11
av_write_trailer(formatContext)=== 0
av_frame_free(&frame);
=============================================================stop=========================================================================
后面这个写入一直是-11,我没玩过FFmpeg,对这玩意不够熟悉