新增U盘获取图语License功能

This commit is contained in:
2024-08-06 20:32:02 +08:00
parent f0b1152cad
commit 1f7bc017ca
27 changed files with 1325 additions and 481 deletions

View File

@@ -1,3 +1,255 @@
// FFmpegDecoder.cpp
//#include "FFmpegDecoder.h"
//
//FFmpegDecoder::FFmpegDecoder(QObject* parent) :
// QThread(parent),
// videoLabel(nullptr),
// abort(false),
// restart(false),
// formatContext(nullptr),
// codecContext(nullptr),
// frame(nullptr),
// packet(nullptr),
// swsContext(nullptr),
// videoStreamIndex(-1) // 初始化成员变量
//{
// av_log_set_level(AV_LOG_QUIET); // 设置日志级别为安静模式
// avformat_network_init(); // 初始化网络
//}
//
//FFmpegDecoder::~FFmpegDecoder()
//{
// mutex.lock();
// abort = true;
// condition.wakeOne();
// mutex.unlock();
// wait();
// if (codecContext) {
// avcodec_free_context(&codecContext);
// }
// if (frame) {
// av_frame_free(&frame);
// }
// if (packet) {
// av_packet_free(&packet);
// }
// if (swsContext) {
// sws_freeContext(swsContext);
// }
// if (formatContext) {
// avformat_close_input(&formatContext);
// }
// avformat_network_deinit(); // 反初始化网络
//}
//
//void FFmpegDecoder::initialize()
//{
// // 初始化FFmpeg库
// avformat_network_init();
//}
//
//void FFmpegDecoder::decodeFile(const QString& filePath, QLabel* videoLabel)
//{
// QMutexLocker locker(&mutex);
// this->filePath = filePath;
// this->videoLabel = videoLabel;
// if (!isRunning()) {
// //start(LowPriority);
// start(NormalPriority);
// }
// restart = true;
// condition.wakeOne();
//}
//
//void FFmpegDecoder::run()
//{
// QFile file(filePath);
// qint64 fileSize = 0;
//
// for (;;) {
// mutex.lock();
// while (!restart && !abort) {
// condition.wait(&mutex);
// }
// if (abort) {
// mutex.unlock();
// break;
// }
// restart = false;
// QLabel* currentVideoLabel = videoLabel;
// QSize labelSize = currentVideoLabel->size();
// mutex.unlock();
// qDebug() << "Video label size: Width =" << labelSize.width() << ", Height =" << labelSize.height();
//
// if (!file.open(QIODevice::ReadOnly)) {
// qWarning() << "Failed to open file:" << filePath;
// continue;
// }
// // 从上次处理的位置开始读取
// file.seek(fileSize);
//
// formatContext = nullptr;
// codecContext = nullptr;
// frame = nullptr;
// packet = nullptr;
//
// // 通过 FFmpeg 初始化格式上下文和解码器
// if (avformat_open_input(&formatContext, filePath.toStdString().c_str(), nullptr, nullptr) != 0) {
// qWarning() << "Failed to open file with FFmpeg:" << filePath;
// file.close();
// continue;
// }
//
// if (avformat_find_stream_info(formatContext, nullptr) < 0) {
// qWarning() << "Failed to retrieve stream info";
// avformat_close_input(&formatContext);
// file.close();
// continue;
// }
//
// videoStreamIndex = -1;
// for (unsigned int i = 0; i < formatContext->nb_streams; ++i) {
// if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
// videoStreamIndex = i;
// break;
// }
// }
// if (videoStreamIndex == -1) {
// qWarning() << "No video stream found";
// avformat_close_input(&formatContext);
// file.close();
// continue;
// }
//
// AVCodecParameters* codecParameters = formatContext->streams[videoStreamIndex]->codecpar;
// const AVCodec* codec = avcodec_find_decoder(codecParameters->codec_id);
// if (!codec) {
// qWarning() << "Unsupported codec";
// avformat_close_input(&formatContext);
// file.close();
// continue;
// }
//
// codecContext = avcodec_alloc_context3(codec);
// if (!codecContext) {
// qWarning() << "Failed to allocate codec context";
// avformat_close_input(&formatContext);
// file.close();
// continue;
// }
//
// if (avcodec_parameters_to_context(codecContext, codecParameters) < 0) {
// qWarning() << "Failed to copy codec parameters to context";
// avcodec_free_context(&codecContext);
// avformat_close_input(&formatContext);
// file.close();
// continue;
// }
//
// if (avcodec_open2(codecContext, codec, nullptr) < 0) {
// qWarning() << "Failed to open codec";
// avcodec_free_context(&codecContext);
// avformat_close_input(&formatContext);
// file.close();
// continue;
// }
//
// frame = av_frame_alloc();
// packet = av_packet_alloc();
//
// // 主解码循环
// while (!abort) {
// qint64 currentFileSize = file.size();
// if (currentFileSize > fileSize) {
// fileSize = currentFileSize;
// file.seek(fileSize); // 设置文件读取位置到末尾
//
// // 读取并处理数据包
// while (av_read_frame(formatContext, packet) >= 0) {
// if (packet->stream_index == videoStreamIndex) {
// int ret = avcodec_send_packet(codecContext, packet);
// if (ret < 0) {
// qWarning() << "Error sending packet for decoding";
// av_packet_unref(packet);
// continue;
// }
// while (ret >= 0) {
// ret = avcodec_receive_frame(codecContext, frame);
// if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
// qWarning() << "----------- break";
// av_packet_unref(packet);
// continue;
// //break;
// }
// else if (ret < 0) {
// qWarning() << "Error during decoding";
// break;
// }
//
// /*mutex.lock();
// QSize labelSize = currentVideoLabel->size();
// mutex.unlock();*/
// //qDebug() << "Video label size: Width =" << labelSize.width() << ", Height =" << labelSize.height();
// QImage img = avFrameToQImage(frame);
// QImage scaledImage = img.scaled(labelSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
// currentVideoLabel->setPixmap(QPixmap::fromImage(scaledImage));
// //currentVideoLabel->setPixmap(QPixmap::fromImage(img));
// QThread::msleep(10); // Simulate 25 FPS frame rate
// }
// }
// av_packet_unref(packet);
// }
// }
//
// mutex.lock();
// if (restart) {
// restart = false;
// mutex.unlock();
// break;
// }
// mutex.unlock();
// }
//
// avcodec_free_context(&codecContext);
// avformat_close_input(&formatContext);
// av_frame_free(&frame);
// av_packet_free(&packet);
// file.close();
// sws_freeContext(swsContext);
//
// mutex.lock();
// if (!restart) {
// condition.wait(&mutex);
// }
// mutex.unlock();
// }
//}
//
//
//QImage FFmpegDecoder::avFrameToQImage(AVFrame* frame)
//{
// int width = frame->width;
// int height = frame->height;
// AVPixelFormat pixFmt = (AVPixelFormat)frame->format;
//
// SwsContext* swsCtx = sws_getContext(width, height, pixFmt, width, height, AV_PIX_FMT_RGB24, SWS_BILINEAR, nullptr, nullptr, nullptr);
// if (!swsCtx) {
// qWarning() << "Failed to initialize the conversion context";
// return QImage();
// }
//
// QImage img(width, height, QImage::Format_RGB888);
// uint8_t* dest[4] = { img.bits(), nullptr, nullptr, nullptr };
// int destLinesize[4] = { img.bytesPerLine(), 0, 0, 0 };
//
// sws_scale(swsCtx, frame->data, frame->linesize, 0, height, dest, destLinesize);
// sws_freeContext(swsCtx);
//
// return img;
//}
//
//
// FFmpegDecoder.cpp
#include "FFmpegDecoder.h"
@@ -15,35 +267,25 @@ FFmpegDecoder::FFmpegDecoder(QObject* parent) :
{
av_log_set_level(AV_LOG_QUIET); // 设置日志级别为安静模式
avformat_network_init(); // 初始化网络
qDebug() << "FFmpegDecoder created";
}
FFmpegDecoder::~FFmpegDecoder()
{
qDebug() << "Destroying FFmpegDecoder";
mutex.lock();
abort = true;
condition.wakeOne();
mutex.unlock();
wait();
if (codecContext) {
avcodec_free_context(&codecContext);
}
if (frame) {
av_frame_free(&frame);
}
if (packet) {
av_packet_free(&packet);
}
if (swsContext) {
sws_freeContext(swsContext);
}
if (formatContext) {
avformat_close_input(&formatContext);
}
cleanup();
avformat_network_deinit(); // 反初始化网络
qDebug() << "FFmpegDecoder destroyed";
}
void FFmpegDecoder::initialize()
{
qDebug() << "Initializing FFmpeg library";
// 初始化FFmpeg库
avformat_network_init();
}
@@ -54,7 +296,7 @@ void FFmpegDecoder::decodeFile(const QString& filePath, QLabel* videoLabel)
this->filePath = filePath;
this->videoLabel = videoLabel;
if (!isRunning()) {
//start(LowPriority);
qDebug() << "Starting decoder thread";
start(NormalPriority);
}
restart = true;
@@ -66,13 +308,14 @@ void FFmpegDecoder::run()
QFile file(filePath);
qint64 fileSize = 0;
for (;;) {
while (true) {
mutex.lock();
while (!restart && !abort) {
condition.wait(&mutex);
}
if (abort) {
mutex.unlock();
qDebug() << "Decoder thread aborting";
break;
}
restart = false;
@@ -85,78 +328,14 @@ void FFmpegDecoder::run()
qWarning() << "Failed to open file:" << filePath;
continue;
}
// 从上次处理的位置开始读取
file.seek(fileSize);
formatContext = nullptr;
codecContext = nullptr;
frame = nullptr;
packet = nullptr;
// 通过 FFmpeg 初始化格式上下文和解码器
if (avformat_open_input(&formatContext, filePath.toStdString().c_str(), nullptr, nullptr) != 0) {
qWarning() << "Failed to open file with FFmpeg:" << filePath;
if (!initializeFFmpeg(filePath)) {
qDebug() << "Failed to initialize FFmpeg for file:" << filePath;
cleanup();
file.close();
continue;
}
if (avformat_find_stream_info(formatContext, nullptr) < 0) {
qWarning() << "Failed to retrieve stream info";
avformat_close_input(&formatContext);
file.close();
continue;
}
videoStreamIndex = -1;
for (unsigned int i = 0; i < formatContext->nb_streams; ++i) {
if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
break;
}
}
if (videoStreamIndex == -1) {
qWarning() << "No video stream found";
avformat_close_input(&formatContext);
file.close();
continue;
}
AVCodecParameters* codecParameters = formatContext->streams[videoStreamIndex]->codecpar;
const AVCodec* codec = avcodec_find_decoder(codecParameters->codec_id);
if (!codec) {
qWarning() << "Unsupported codec";
avformat_close_input(&formatContext);
file.close();
continue;
}
codecContext = avcodec_alloc_context3(codec);
if (!codecContext) {
qWarning() << "Failed to allocate codec context";
avformat_close_input(&formatContext);
file.close();
continue;
}
if (avcodec_parameters_to_context(codecContext, codecParameters) < 0) {
qWarning() << "Failed to copy codec parameters to context";
avcodec_free_context(&codecContext);
avformat_close_input(&formatContext);
file.close();
continue;
}
if (avcodec_open2(codecContext, codec, nullptr) < 0) {
qWarning() << "Failed to open codec";
avcodec_free_context(&codecContext);
avformat_close_input(&formatContext);
file.close();
continue;
}
frame = av_frame_alloc();
packet = av_packet_alloc();
// 主解码循环
while (!abort) {
qint64 currentFileSize = file.size();
@@ -176,24 +355,17 @@ void FFmpegDecoder::run()
while (ret >= 0) {
ret = avcodec_receive_frame(codecContext, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
qWarning() << "----------- break";
av_packet_unref(packet);
continue;
//break;
}
else if (ret < 0) {
qWarning() << "Error during decoding";
break;
}
/*mutex.lock();
QSize labelSize = currentVideoLabel->size();
mutex.unlock();*/
//qDebug() << "Video label size: Width =" << labelSize.width() << ", Height =" << labelSize.height();
QImage img = avFrameToQImage(frame);
QImage scaledImage = img.scaled(labelSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
currentVideoLabel->setPixmap(QPixmap::fromImage(scaledImage));
//currentVideoLabel->setPixmap(QPixmap::fromImage(img));
QThread::msleep(10); // Simulate 25 FPS frame rate
}
}
@@ -210,12 +382,8 @@ void FFmpegDecoder::run()
mutex.unlock();
}
avcodec_free_context(&codecContext);
avformat_close_input(&formatContext);
av_frame_free(&frame);
av_packet_free(&packet);
cleanup();
file.close();
sws_freeContext(swsContext);
mutex.lock();
if (!restart) {
@@ -225,25 +393,102 @@ void FFmpegDecoder::run()
}
}
bool FFmpegDecoder::initializeFFmpeg(const QString& filePath)
{
if (avformat_open_input(&formatContext, filePath.toStdString().c_str(), nullptr, nullptr) != 0) {
qWarning() << "Failed to open file with FFmpeg:" << filePath;
return false;
}
if (avformat_find_stream_info(formatContext, nullptr) < 0) {
qWarning() << "Failed to retrieve stream info";
return false;
}
videoStreamIndex = -1;
for (unsigned int i = 0; i < formatContext->nb_streams; ++i) {
if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
break;
}
}
if (videoStreamIndex == -1) {
qWarning() << "No video stream found";
return false;
}
AVCodecParameters* codecParameters = formatContext->streams[videoStreamIndex]->codecpar;
const AVCodec* codec = avcodec_find_decoder(codecParameters->codec_id);
if (!codec) {
qWarning() << "Unsupported codec";
return false;
}
codecContext = avcodec_alloc_context3(codec);
if (!codecContext) {
qWarning() << "Failed to allocate codec context";
return false;
}
if (avcodec_parameters_to_context(codecContext, codecParameters) < 0) {
qWarning() << "Failed to copy codec parameters to context";
return false;
}
if (avcodec_open2(codecContext, codec, nullptr) < 0) {
qWarning() << "Failed to open codec";
return false;
}
frame = av_frame_alloc();
packet = av_packet_alloc();
return true;
}
void FFmpegDecoder::cleanup()
{
if (codecContext) {
avcodec_free_context(&codecContext);
codecContext = nullptr;
}
if (frame) {
av_frame_free(&frame);
frame = nullptr;
}
if (packet) {
av_packet_free(&packet);
packet = nullptr;
}
if (swsContext) {
sws_freeContext(swsContext);
swsContext = nullptr;
}
if (formatContext) {
avformat_close_input(&formatContext);
formatContext = nullptr;
}
}
QImage FFmpegDecoder::avFrameToQImage(AVFrame* frame)
{
int width = frame->width;
int width = frame->width;
int height = frame->height;
AVPixelFormat pixFmt = (AVPixelFormat)frame->format;
SwsContext* swsCtx = sws_getContext(width, height, pixFmt, width, height, AV_PIX_FMT_RGB24, SWS_BILINEAR, nullptr, nullptr, nullptr);
if (!swsCtx) {
qWarning() << "Failed to initialize the conversion context";
return QImage();
if (!swsContext) {
swsContext = sws_getContext(width, height, pixFmt, width, height, AV_PIX_FMT_RGB24, SWS_BILINEAR, nullptr, nullptr, nullptr);
if (!swsContext) {
qWarning() << "Failed to initialize the conversion context";
return QImage();
}
}
QImage img(width, height, QImage::Format_RGB888);
uint8_t* dest[4] = { img.bits(), nullptr, nullptr, nullptr };
int destLinesize[4] = { img.bytesPerLine(), 0, 0, 0 };
sws_scale(swsCtx, frame->data, frame->linesize, 0, height, dest, destLinesize);
sws_freeContext(swsCtx);
sws_scale(swsContext, frame->data, frame->linesize, 0, height, dest, destLinesize);
return img;
}

View File

@@ -36,6 +36,9 @@ public:
void decodeFile(const QString& filePath, QLabel* videoLabel);
void decodeSingleFrame(const QByteArray& data, QLabel* videoLabel); // 添加 videoLabel 参数
bool initializeFFmpeg(const QString& filePath);
void cleanup();
protected:
void run() override;