#ifndef IMAGE_PROCESSOR_H
#define IMAGE_PROCESSOR_H
#include <QObject>
#include <QImage>
#include <QByteArray>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}
class ImageProcessor : public QObject
{
Q_OBJECT
public:
explicit ImageProcessor(QObject *parent = nullptr);
~ImageProcessor();
void processImage(const QByteArray& imageData, QImage& image);
signals:
void imageProcessed(const QImage &image);
private:
AVCodec *decoder;
AVCodecContext *decoderContext;
SwsContext *swsContext;
};
#endif // IMAGE_PROCESSOR_H
#include "image_processor.h"
#include <QDebug>
ImageProcessor::ImageProcessor(QObject *parent) : QObject(parent)
{
av_register_all();
avcodec_register_all();
decoder = avcodec_find_decoder(AV_CODEC_ID_MJPEG);
if (!decoder) {
qDebug() << "Could not find decoder";
return;
}
decoderContext = avcodec_alloc_context3(decoder);
if (!decoderContext) {
qDebug() << "Could not allocate codec context";
return;
}
if (avcodec_open2(decoderContext, decoder, nullptr) < 0) {
qDebug() << "Could not open codec";
return;
}
}
ImageProcessor::~ImageProcessor()
{
if (decoderContext) {
avcodec_free_context(&decoderContext);
}
if (swsContext) {
sws_freeContext(swsContext);
}
}
void ImageProcessor::processImage(const QByteArray &imageData, QImage& image)
{
AVPacket packet;
av_init_packet(&packet);
packet.data = reinterpret_cast<uint8_t*>(const_cast<char*>(imageData.data()));
packet.size = imageData.size();
AVFrame *frame = av_frame_alloc();
if (!frame) {
qDebug() << "Could not allocate frame";
return;
}
if (avcodec_send_packet(decoderContext, &packet) < 0) {
qDebug() << "Error sending packet to decoder";
av_frame_free(&frame);
return;
}
if (avcodec_receive_frame(decoderContext, frame) < 0) {
qDebug() << "Error receiving frame from decoder";
av_frame_free(&frame);
return;
}
int newWidth = decoderContext->width;
int newHeight = decoderContext->height;
swsContext = sws_getContext(
decoderContext->width, decoderContext->height, decoderContext->pix_fmt,
newWidth, newHeight, AV_PIX_FMT_RGB24,
SWS_BILINEAR, nullptr, nullptr, nullptr
);
if (!swsContext) {
qDebug() << "Could not allocate sws context";
av_frame_free(&frame);
return;
}
AVFrame *outputFrame = av_frame_alloc();
if (!outputFrame) {
qDebug() << "Could not allocate output frame";
sws_freeContext(swsContext);
av_frame_free(&frame);
return;
}
outputFrame->format = AV_PIX_FMT_RGB24;
outputFrame->width = newWidth;
outputFrame->height = newHeight;
if (av_frame_get_buffer(outputFrame, 0) < 0) {
qDebug() << "Could not allocate output frame buffer";
sws_freeContext(swsContext);
av_frame_free(&outputFrame);
av_frame_free(&frame);
return;
}
sws_scale(swsContext, frame->data, frame->linesize, 0, decoderContext->height,
outputFrame->data, outputFrame->linesize);
QImage img(newWidth, newHeight, QImage::Format_RGB888);
for (int y = 0; y < newHeight; ++y) {
memcpy(img.scanLine(y), outputFrame->data[0] + y * outputFrame->linesize[0], newWidth * 3);
}
emit imageProcessed(img);
sws_freeContext(swsContext);
av_frame_free(&outputFrame);
av_frame_free(&frame);
img.swap(image);
}
在做网络投屏时,遇到接收数据后在加载到QImage时,时不时的就会出现加载图片失败,导致实时投屏显示花屏、闪烁,就行借用了ffmpeg 对图片数据的处理能力。处理好后绘制到QT界面上。